【问题标题】:Can I reinterpret_cast the parameter of a constexpr function?我可以重新解释 constexpr 函数的参数吗?
【发布时间】:2020-09-24 06:49:50
【问题描述】:

我想编写一个在编译时评估的函数,它需要一个指向 4 字节数组的指针,并输出一个与该数组具有相同位模式的 int。 所以我想出了:

constexpr int f(const char* p) {
     return *reinterpret_cast<int*>(p);
}

然后,我想像这样使用f()

switch(x) {
case f("GOOG"):
   // do something
case f("MSFT"):
   // do something
case f("NIKE"):
  // do something
}

但是,我遇到了编译器错误:

错误:通过常量表达式 case f("GOOG") 中的“int”glvalue 访问“GOOG”的值
  1. 如何修复 f() 使其编译?
  2. 是否有更好的方法来实现相同的目标?

【问题讨论】:

  • 即使编译了,也是严格的别名违规和UB。使用位移从单个 chars 中生成整数。
  • @HolyBlackCat 谢谢。顺便说一句,什么是 UB?
  • UB 是未定义的行为。
  • 谢谢。我觉得进行 4 次位移并不像将其视为 int 那样优雅。有没有办法安全地做到这一点?
  • 你也可以在其中创建一个intmemcpy数组,但是memcpy不是constexpr

标签: c++ compiler-errors bit-manipulation c++17 constexpr


【解决方案1】:

恭喜,您已经激活了严格别名陷阱卡,并且您的代码具有未定义的行为(如果可以编译的话)。

您的代码中几乎没有错误,“正确”的版本是:

 constexpr int f(const char* p) {
         return *reinterpret_cast<const int*>(p);
    }
  • reinterpret_cast不能抛弃const
  • cursor-&gt;p错字?

但由于const char* 不指向int,因此对其进行强制转换会破坏严格的别名规则。 int 不是可以给其他人起别名的类型之一 - 只有 std::byte, (unsigned) char 可以。

最干净的应该是这样的:

#include <cstring>

constexpr int f(const char* p) {
         int val = 0;
         static_assert(sizeof(val)==4); // If the array is 4-byte long.
         std::memcpy(&val,p,sizeof val);
         return val;
    }

但是std::memcpy 不是constexpr,即使在运行时这也可能没有任何开销,编译器可以识别这一点并自行重新解释字节。

所以使用位移:

constexpr int f(const char* p) {
       int value=0;
       using T = decltype (value);
       for(std::size_t i =0; i< sizeof(T);++i)
        value|= (T)p[i] << (8*i);

    return value;
    }

int main(){

    // @ == 64
    // 1077952576 = 01000000 01000000 01000000 01000000
    static_assert(f("@@@@") ==1077952576);
}

只是为了迂腐"@@@@" 的长度是 5,而不是 4。

【讨论】:

  • 光标错了。固定的。泰。
  • 你能解释一下这个value|= (T)*p &lt;&lt; (8*i);在做什么吗?看起来它只使用 p 的第一个字符,左移 1 个字节,并按位或值进行运算。 IE。它使用其余的字符吗? p[1]、p[2] 等
  • @ijklr 哎呀,对不起,它当然缺少索引,我太傻了,因为我做了一个太简单的测试用例。固定。
  • 谢谢。而你使用(T) 而不是reinterpret_cast&lt;T&gt; 的原因是因为在constexpr 函数内部,你不能重新解释_cast,对吧?
  • 我希望我可以将它转换为 int 而不需要循环:(
猜你喜欢
  • 2015-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多