c++ - 创建返回较窄类型的自定义 sizeof()

标签 c++ templates

问题

sizeof 返回 size_t 类型,因此当作为参数传递给采用较窄类型(例如 unsigned char)的函数时,会发生隐式转换.在许多情况下,这些是第 3 方库函数,因此它们的原型(prototype)超出了我的控制范围。编译器现在通常足够聪明,可以检测此类转换是否真的会导致截断并警告您,但一些静态代码分析器仍会将此类情况标记出来,从而导致大量误报。显式转换 sizeof 的结果通常可以解决分析警告,但它会隐藏编译器警告,更不用说它会使事情变得笨拙。

我的解决方案

template<class T1, class T2>
struct sizeofxx {
    static constexpr T2 value{ sizeof(T1) };
};

template <class T>
constexpr unsigned int sizeof32 = sizeofxx<T, unsigned int>::value;

template <class T>
constexpr unsigned short sizeof16 = sizeofxx<T, unsigned short>::value;

template <class T>
constexpr unsigned char sizeof8 = sizeofxx<T, unsigned char>::value;

用法:

unsigned int foo = sizeof32<float>;
const char bar[255];
unsigned char foo3 = sizeof8<decltype(bar)>;

它依靠聚合初始化来防止在编译时缩小转换。因此,如果我使用了 bar[256],构建就会失败。

限制

但如您所见,在变量上使用它相当笨拙(由于需要 decltype)。有没有更简单的方法来做到这一点?我知道一种方法是将它包装在一个宏中,但这会阻止像 Visual Studio 这样的 IDE 在您将鼠标悬停在它上面时帮助您解析该值。另一种方法是创建一个 constexpr 函数:

template <class T1>
constexpr unsigned char sizeof8f(T1&) {
    return sizeof(T1);
}

但这也不允许 IDE 代码时间解析,并且会增加所涉及的符号数量,因为它们需要与早期对类型进行操作的实现具有不同的名称。

欢迎就解决根本问题(静态代码分析警告)提出任何其他建议。不,压制它们是不可行的。

最佳答案

对于您的特定问题,即使在调试版本上也不需要像某些人建议的那样进行任何运行时检查,因为该值本身就是一个 constexpr。您可以编写一个简单的实用程序,将一个值转换为能够容纳它的最小类型。

template<size_t N>
inline constexpr auto minuint = []{
    if constexpr(N >= 1ull << 32)
        return N;
    else if constexpr(N >= 1ull << 16)
        return uint32_t(N);
    else if constexpr(N >= 1ull << 8)
        return uint16_t(N);
    else
        return uint8_t(N);
}();

另一方面,没有函数或模板可以同时接受表达式和类型。 模仿 sizeof 行为的唯一可能方法是使用宏。

#define Sizeof(x) minuint<sizeof(x)>

这样一来,您就永远不会收到有关缩小转化率的错误警告:如果有警告,则表明您做错了什么。

关于c++ - 创建返回较窄类型的自定义 sizeof(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72871781/

相关文章:

c++ - 如何让编译器推断模板的返回类型?

c++ - 如何让 `static_assert` 打印失败时得到的值?

c++ - 如何打破定义嵌套模板类的 header 的循环依赖?

c++ - 从命令行构建 Visual Studio 2008 解决方案

c++ - 为什么 Code::Blocks 显示错误的多重定义?

c++ - 模板特化取决于类型

c++ - 模板一个类似 python 的 setattr 函数

c++ - 为什么我不能从函数返回 Boost::Scoped_ptr?

带有模板的 C++ 函数指针参数

rest - 使用 DocuSign REST API 获取/设置模板字段