为什么constexpr在编译时没有被评估(MSVC 2015)?

时间:2016-05-04 17:09:34

标签: c++11 visual-c++ hash constexpr compile-time

最近我试图在MSVC 2015下利用C ++ 0x constexpr,我的目标是实现编译时哈希字符串。我编写了一个简单的FNV-1a哈希算法作为constexpr函数,根据需要使用单个return语句(三元运算符)并仅调用constexpr函数,这里是:

template <size_t N>
constexpr U32 StringID_FNV1a_32(const char(&str)[N], I32 charIndex = 0, U32 hash = 2166136261U)
{
    return charIndex < N-1 ? StringID_FNV1a_32(str, charIndex +1, (hash ^ str[charIndex]) * 16777619U) : hash;
}

我还做了一个小宏,能够毫不费力地改变算法:

#define STRING_ID(str)  core::utility::StringID_FNV1a_32(str)

然后我在我的代码中使用了这个宏,仔细检查是否有任何断点,以及生成的汇编代码。这是小情景:

//1. normal variable test
U32 hash1 = STRING_ID("abc");  

//2. enum test
enum {    
    hash2 = STRING_ID("abc")
};

//3. constexpr variable test
constexpr U32 hash3 = STRING_ID("abc");

这里有事实:

  1. 第一次测试是在运行时
  2. 调用的
  3. 在编译时执行第二次测试
  4. 运行时
  5. 调用第三个测试

    你可以想象我对第一次和第三次尝试感到有些困惑。

    为什么第三种情况是允许编译器在运行时调用该函数?即使msdn明确说明“const和constexpr变量之间的主要区别在于const变量的初始化可以延迟到运行时,而constexpr变量必须在编译时初始化。” [{ {3}}

    可能与我处于调试模式且所有优化都已关闭的事实有关?那么第一次测试呢?有没有办法强制编译器在编译时执行散列?

1 个答案:

答案 0 :(得分:1)

MSVC的行为可能很奇怪,但是可以强制它使constexpr函数在编译时运行。

#define COMPILE_TIME(value) ((decltype(value))CompileTime<decltype(value), value>::ValueHolder::VALUE)

template<typename T, T Value>
struct CompileTime
{
    enum class ValueHolder : T
    {
        VALUE = Value
    };
};

这会强制将值作为模板参数+枚举值传递,从而使其仅限于编译时。
另请注意,这仅适用于整数类型。

你可以简单地通过调用constexpr函数作为COMPILE_TIME宏的参数来使用它:

constexpr U32 hash = COMPILE_TIME(STRING_ID("abc"));