首页 > 解决方案 > 局部常量变量不是 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)

编译失败:

错误 C2131:表达式未计算为常量

注意:失败是由在其生命周期之外读取变量引起的

注意:请参阅“字节”的用法

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

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

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

解决方案


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

假设您的 Hash 函数如下所示:

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;
}

推荐阅读