使用 gsl::narrow 失败

Using gsl::narrow fails

提问人:Andrew Truckle 提问时间:10/3/2021 最后编辑:Adrian MoleAndrew Truckle 更新时间:10/4/2021 访问量:175

问:

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

我觉得有点讽刺的是,代码分析警告的原因是它告诉我在两个实例中使用: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 型强制转换或函数式强制转换

兜圈子!鉴于当时的情况,我是否应该明白正确的前进方向是:

  1. 使用和...reinterpret_cast
  2. 添加适当的警告以禁止显示警告。prama

正确?

visual-c++ 代码分析 重新解释转换 cpp-core-guidelines

评论

0赞 MicroVirus 10/3/2021
对不起,我没有完全遵循,尤其是关于兜圈子。 它能做什么受到限制(在某种程度上它是“安全的”)。这两种转换都不是“编译时检查正确”的,因此您不能使用,并且错误消息会告诉您可以使用哪些强制转换。static_caststatic_cast
0赞 Andrew Truckle 10/4/2021
@MicroVirus 平心而论,原始代码是 C 样式的转换。警告建议 gsl::narrow 等。但是我已经改用了reinterpret_cast和编译指示抑制。
1赞 Adrian Mole 10/4/2021
或。。。自己滚动(视频下图)pointer_cast
0赞 Andrew Truckle 10/4/2021
@AdrianMole 我的?以前从未这样做过!!!!pointer_cast

答:

1赞 Adrian Mole 10/4/2021 #1

您不能(也不应该尝试)使用 a 以外的任何值在指针和非指针之间或指向不同(不相关)类型的指针之间进行转换。该函数只是 : 了解 gsl::narrow 实现的“花哨”版本。reinterpret_castgsl::narrowstatic_cast

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

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

注意:关于 __pragma() 指令(而不是 #pragma)的使用,请参阅此处

评论

0赞 Andrew Truckle 10/4/2021
棒。一个巧妙的主意!除了第三部分库之外,我正在我使用的整个项目中推出它。reinterpret_cast
0赞 Andrew Truckle 10/4/2021
对此的一个观察结果是,代码分析现在正在标记,说它可以添加这个词。思潮?pointer_castnoexcept
1赞 Adrian Mole 10/4/2021
@Andrew 好吧,我该和代码分析器争论谁呢?见编辑。