在constexpr中用工会取代reinterpret_cast - 好主意?

问题描述 投票:0回答:2

我正在使用此代码将指针转换为size_t,它用于::std::hash函数,该函数应该在编译时散列给定指针,并且因为reinterpret_cast中不允许使用constexprs,所以我提出了以下解决方案,它可以作为预计,但我想知道这是否可以被视为一个好主意。如果您能给我一些关于这段代码实际可移植性的指示,那也很棒。

union {
   size_t datr;
   void* pointer;
} dummy{.pointer = (void*) somePointer};
size_t pointerAsAsize_t = dummy.datr; // how portable is this?

有没有更好的解决方案 - 如上所述,我想创建一个在编译时运行的::std::hash<some_pointer*>

c++ c++11 union constexpr
2个回答
4
投票

如果您尝试在常量表达式上下文中执行该操作(即:当编译器被迫在编译时调用您的代码时,例如导致数组大小或模板参数的表达式),您将发现它将无法编译。 Constexpr执行要求在编译时会引起UB的任何事情都会变成格式错误。并且由于您的代码激发了UB(通过访问非活动的联合成员),它将无法编译。

All three major compilers will fail on this在一个恒定表达的背景下。 MSVC(令人惊讶)给出了最好,最直接的错误消息:

(13):错误C2131:表达式没有评估为常量 (9):注意:失败是由访问工会的非活跃成员引起的 (9):注意:看看'foo :: Foo :: integer'的用法

您的代码可能“按预期工作”只是因为您在编译器不必在编译时执行它时调用它。鉴于GCC / Clang的错误,如果您将它用作堆栈上数组的数组大小,它可能会调用GCC / Clang的可变长度数组语言扩展。如果你关闭它,你的代码可能无法编译。我的例子使它成为一个全局数组,不允许使用VLA。


有没有更好的解决方案

不。如果您提供指针(或包含指针的类型)作为源或目标,那么即使C++20's bit_cast也不会是constexpr。编译时指针是真实的东西,而不仅仅是代表地址的数字;将它们转换为整数或从整数转换在编译时根本不是一个合理的活动。

编译时指针必须指向编译时存在的事物。无法知道它们在运行时的位置。因此,散列指针的编译时值(甚至是指向静态/全局对象的指针)的想法从一开始就注定要失败。


-1
投票

我认为在大多数的这些代码上都可以使用这个代码,但正式情况下它不能。 size_t是一个无符号类型,用于保存结果sizeof(xxx) constructrion。无法保证足够大以存储指针。您可以添加static_assert(sizeof(size_t) == sizeof(void*),"")或使用std::intptr_t(如果它在您的库中可用)。

© www.soinside.com 2019 - 2024. All rights reserved.