c++ - 局部常量变量不是 constexpr 可评估的,但无法弄清楚为什么

标签 c++ visual-c++ c++17 constexpr

我正在尝试将一个 int 作为参数并单独对其字节进行操作,例如采用 0xDEADF00D 并逐个处理每个字节:0xDE 0xAD 0xF0 0x0D

为此,我编写了以下代码:

template <int state, int seed>
constexpr static uint32_t CalculateRandomFromState()
{
    const char bytes[4] = {
        (state >> 24) & 0xFF,
        (state >> 16) & 0xFF,
        (state >> 8) & 0xFF,
         state & 0xFF,
    };

    constexpr auto value = Compiletime::Hash<seed, sizeof(bytes)>(bytes);

    return value;
}

HashFn 的 sig 是:

template <const uint32_t seed, const uint32_t size = NULL>
constexpr uint32_t Hash(const char* message)

编译失败:

error C2131: expression did not evaluate to a constant

note: failure was caused by a read of a variable outside its lifetime

note: see usage of 'bytes'

我在 StackOverflow 上阅读了关于参数可能无法在编译时求值的主题,(这就是为什么我将大部分参数切换为模板变量的原因,因此 100% 保证它们在编译时) 但在这种情况下,它给出错误的原因似乎不符合逻辑。 bytes 值取决于编译时值,byte 也是常量。

为什么它会超出它的生命周期?如果我让我们说 "somestring" 而不是变量 bytes 然后它编译完美。 这里有什么不是常量可评估的?

最佳答案

函数声明中的

constexpr 不要求所有求值路径都指向常量表达式。函数调用的结果是否为 constexpr 取决于输入参数。

假设您的哈希函数如下所示:

template <uint32_t seed, uint32_t size>
constexpr uint32_t Hash(const char* message)
{
    uint32_t rc = seed;
    for (uint32_t i = 0; i < size; ++i)
        rc += message[i];
    return rc;
}

message 是常量表达式时,这将计算为常量表达式。

但是你用一个非常量表达式调用它:

    const char bytes[4] = {
        (state >> 24) & 0xFF,
        (state >> 16) & 0xFF,
        (state >> 8) & 0xFF,
         state & 0xFF,
    };

    constexpr auto value = Compiletime::Hash<seed, sizeof(bytes)>(bytes);

每次 Hash(bytes) 被调用时,bytes 可能会有不同的地址。

您可以通过简单地声明 bytes constexpr 使其工作:

template <int state, int seed>
constexpr static uint32_t CalculateRandomFromState()
{
    constexpr char bytes[4] = {
        (state >> 24) & 0xFF,
        (state >> 16) & 0xFF,
        (state >> 8) & 0xFF,
         state & 0xFF,
    };

    constexpr auto value = Compiletime::Hash<seed, sizeof(bytes)>(bytes);

    return value;
}

关于c++ - 局部常量变量不是 constexpr 可评估的,但无法弄清楚为什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55353504/

相关文章:

windows - 在 Windows 上编译用 Zig 编写的 CPython 扩展

c++ - 数组初始化

c++ - 构造一个没有默认构造函数的空对象

c++ - glfwDestroyWindow 不会关闭窗口

c++ - 在 Rcpp 中选择一个不连续的子矩阵

c++ - 如何将可变大小的指针数组作为参数传递给函数

c - Visual C++ 无法识别注释行?

C++ 从 ‘const type* const’ 到 ‘type*’ 的无效转换

c++ - 推导引用模板参数的类型

c++ - 获取C++类成员变量全名