【问题标题】:Using gsl::narrow fails使用 gsl::narrow 失败
【发布时间】:2021-11-24 07:34:42
【问题描述】:

我知道有类似的问题,但我不知道这个问题的最佳措辞。

我觉得有点讽刺的是,代码分析警告的原因首先是它告诉我在两个实例中使用gsl::narrow

实例 1:

auto* pCell1 = gsl::narrow<CGridCellBase*>(lParam1);
auto* pCell2 = gsl::narrow<CGridCellBase*>(lParam2);

编译错误:

    6>D:\My Libraries\GSL-main\include\gsl\util(105,1): error C2440: 'static_cast': cannot convert from 'U' to 'T'
6>        with
6>        [
6>            U=LPARAM
6>        ]
6>        and
6>        [
6>            T=CGridCellBase *
6>        ]
6>D:\My Libraries\GSL-main\include\gsl\util(105,12): message : Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

实例 2:

auto* pItem = gsl::narrow<NM_GRIDVIEW*>(pNotifyStruct);

编译错误:

6>D:\My Libraries\GSL-main\include\gsl\narrow(58,1): error C2440: 'static_cast': cannot convert from 'const T' to 'U'
6>        with
6>        [
6>            T=NM_GRIDVIEW *
6>        ]
6>        and
6>        [
6>            U=NMHDR *
6>        ]
6>D:\My Libraries\GSL-main\include\gsl\narrow(58,9): message : Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

那些消息告诉我做相反的事情:

  • 从整数类型转换为指针类型需要 reinterpret_cast、C 样式转换或函数样式转换
  • 指向的类型不相关;转换需要 reinterpret_cast、C-style cast 或 function-style cast

绕圈子!鉴于当时的情况,我是否理解正确的前进方向是:

  1. 使用reinterpret_cast 和...
  2. 添加适当的prama 警告以抑制警告。

正确吗?

【问题讨论】:

  • 很抱歉我没有完全遵循,特别是关于绕圈子。 static_cast 的功能受到限制(在某种程度上它是“安全的”)。两种转换都不是“编译时检查正确”,因此您不能使用static_cast,错误消息会告诉您可以使用哪些转换。
  • @MicroVirus 平心而论,原始代码是 C 风格的。警告建议 gsl::narrow 等。但我已更改为 reinterpret_cast 和 pragma 抑制。
  • 或者...自己动手pointer_cast(视频下文)
  • @AdrianMole Myown pointer_cast?以前从来没有这样做过!!!!!!

标签: visual-c++ code-analysis reinterpret-cast cpp-core-guidelines


【解决方案1】:

您不能(也不应该尝试)使用 reinterpret_cast 以外的任何东西在指针和非指针之间或指向不同(不相关)类型的指针之间进行转换。 gsl::narrow 函数只是 static_cast 的“花式”版本:Understanding gsl::narrow implementation

此外,在编写使用 WinAPI 或 MFC 的程序时,几乎不可能完全避免在指针和非指针类型之间进行转换;值得注意的是,许多消息处理例程将指向某些数据或其他数据的指针作为其lParam 参数(LPARAM 类型定义为__int64int,具体取决于目标平台)。

所以,恕我直言,您的建议是最好的选择:

  1. 使用reinterpret_cast 和...
  2. 添加适当的编译指示警告以抑制警告。

但是,您很可能需要在代码中的 许多 位置添加 #pragma... 指令。因此,您可以做的是创建自己的“帮助器”(或包装器)演员表,然后您可以在整个代码中使用它。

例如,您可以将以下内容添加到您的“stdafx.h”(或“pch.h”)文件中(或添加到需要转换的任何标题中):

template<typename T, typename U> static T inline pointer_cast(U src) noexcept
{
    static_assert(sizeof(T) >= sizeof(U), "Invalid pointer cast"); // Check sizes!
    __pragma(warning(suppress:26490)) // Note: no semicolon after this expression!
    return reinterpret_cast<T>(src);
}

然后您可以使用 pointer_cast 并避免每次都添加 pragma。下面是一个典型示例,在自定义对话框类中为 WM_NOTIFY 消息使用潜在的消息处理程序:

BOOL MyDialog::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
    NMHDR* pHdr = pointer_cast<NMHDR*>(lParam);
    switch (pHdr->code) {
        //... remaining code ...

注意:关于__pragma() 指令(而不是#pragma)的使用,see here

【讨论】:

  • 太棒了。一个好主意!除了第三方库之外,我将在我使用 reinterpret_cast 的整个项目中推广它。
  • 对此的一个观察是代码分析现在标记pointer_cast,表示它可以添加noexcept这个词。想法?
  • @Andrew 好吧,我有什么资格与代码分析器争论?见编辑。 :-)
猜你喜欢
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2011-08-20
  • 1970-01-01
  • 2012-10-27
  • 2017-04-02
相关资源
最近更新 更多