编译时为什么不评估constexpr(MSVC 2015)?

最近我试图利用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");

这里的事实:

  • 第一次测试在运行时被调用
  • 第二次测试是在编译时进行的
  • 第三次测试在运行时被调用
  • 你可以想象我对第一次和第三次尝试有点困惑。

    为什么在第三种情况下编译器允许在运行时调用该函数? 即使msdn明确指出:“const和constexpr变量的主要区别在于const变量的初始化可以延迟到运行时间,而constexpr变量必须在编译时初始化。” [https://msdn.microsoft.com/it-it/library/dn956974.aspx#Anchor_3]

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


    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"));
    
    链接地址: http://www.djcxy.com/p/68365.html

    上一篇: Why constexpr is not evaluated at compile time (MSVC 2015)?

    下一篇: Runtime function branching on compile