【问题标题】:Why constexpr is not evaluated at compile time (MSVC 2015)?为什么 constexpr 不在编译时评估(MSVC 2015)?
【发布时间】:2016-08-30 06:18:30
【问题描述】:

最近我尝试在 MSVC 2015 下利用 C++0x constexpr,我的目标是实现编译时哈希字符串。我编写了一个简单的 FNV-1a 哈希算法作为 constexpr 函数,根据需要使用单个返回语句(三元运算符)并仅调用 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. 运行时调用了第三个测试

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

为什么在第三种情况下允许编译器在运行时调用函数?尽管 msdn 明确说明 “const 和 constexpr 变量之间的主要区别在于 const 变量的初始化可以推迟到运行时进行,而 constexpr 变量必须在编译时进行初始化。” [@ 987654321@

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

【问题讨论】:

  • 如果你将 "abc" 设为 constexpr string 然后将其传递给函数会发生什么?
  • 如果你在 constexpr 上下文中使用 hash3,比如static_assert(hash3 == hash2, "!");,你会看到正确的值在编译时已经可用。然而由于某种原因,它还在运行时再次计算和初始化,这可能是一个错误。
  • @melak47 你对 static_assert 测试的看法是对的......很奇怪......也许这真的是一个错误......
  • @johnbakers 使用 constexpr char str[4] 作为参数不会改变运行时间

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


【解决方案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"));

【讨论】:

    猜你喜欢
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 2012-12-24
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多