如何让 msvc 14 在编译时评估我的 constexpr
How to make msvc 14 evaluate my constexpr at compile time
我正在试验 C++ constexpr
。我正在使用 FNV-1a 哈希实现 HashedString
class。
除了 visual studio 2015 update 3 似乎没有在编译时评估 constexpr
之外,一切似乎都很好。
我添加了一个 static_assert
并且它没有显示错误,但是在我的测试反汇编中很明显有一个对 constexpr
函数的显式调用而不是预先计算的值。
我也尝试过使用 g++ 和 clang,它们都能够在编译时评估 constexpr
。
这是我的测试代码:
#include <cstdint>
#include <cstddef>
#include <string>
class HashedString {
public:
//value working only for a 32bit hash
constexpr static size_t defaultOffset = 2166136261u;
constexpr static size_t prime = 16777619u;
/**
* Compute the hash of a string at compile time using FNV-1a hash
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80 %93Vo_hash_function
*/
template<std::size_t N>
constexpr HashedString(const char(&a)[N]) noexcept
: mHash(hash(a))
#if defined(_DEBUG)
, mString(a)
#endif
{
}
explicit constexpr HashedString(size_t h) noexcept : mHash(h) {}
constexpr static size_t hash(const char *const aString, const uint32_t val = defaultOffset) noexcept
{
return (aString[0] == '[=10=]') ? val : hash(&aString[1], (val ^ uint32_t(aString[0])) * prime);
}
constexpr bool operator==(const HashedString & hs) const { return mHash == hs.mHash; }
constexpr bool operator==(const size_t & h) const { return mHash == h; }
constexpr bool operator!=(const HashedString & hs) const { return mHash != hs.mHash; }
constexpr bool operator!=(const size_t & h) const { return mHash != h; }
constexpr bool operator<(const HashedString & hs) const { return mHash < hs.mHash; }
private:
const size_t mHash = 0;
#if defined(_DEBUG)
const char* mString = nullptr;
#endif
};
static_assert(HashedString("FNV Hash Test") == 0xF38B3DB9, "HashedString of 'FNV Hash Test' shoulb be equal to 0xF38B3DB9");
int main(int , char**) {
constexpr HashedString hs("FNV Hash Test");
return hs == 0xF38B3DB9;
}
所以我的问题是:有没有办法让 visual studio 在编译时计算我的 constexpr
?
将 main 更改为:
constexpr auto hash = HashedString::hash("FNV Hash Test");
return hash == 0xF38B3DB9;
或
constexpr HashedString hs("FNV Hash Test");
constexpr auto answer = hs == 0xF38B3DB9;
return answer;
将导致在编译时计算散列。您的代码的方式不需要编译器在编译时计算哈希。通过要求编译器初始化一个 constexpr 变量,它被迫在编译时计算值。将 main 的代码减少为:
mov eax,1
ret
哇哦!用于 VS2015 的 SSA 优化。
我正在试验 C++ constexpr
。我正在使用 FNV-1a 哈希实现 HashedString
class。
除了 visual studio 2015 update 3 似乎没有在编译时评估 constexpr
之外,一切似乎都很好。
我添加了一个 static_assert
并且它没有显示错误,但是在我的测试反汇编中很明显有一个对 constexpr
函数的显式调用而不是预先计算的值。
我也尝试过使用 g++ 和 clang,它们都能够在编译时评估 constexpr
。
这是我的测试代码:
#include <cstdint>
#include <cstddef>
#include <string>
class HashedString {
public:
//value working only for a 32bit hash
constexpr static size_t defaultOffset = 2166136261u;
constexpr static size_t prime = 16777619u;
/**
* Compute the hash of a string at compile time using FNV-1a hash
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80 %93Vo_hash_function
*/
template<std::size_t N>
constexpr HashedString(const char(&a)[N]) noexcept
: mHash(hash(a))
#if defined(_DEBUG)
, mString(a)
#endif
{
}
explicit constexpr HashedString(size_t h) noexcept : mHash(h) {}
constexpr static size_t hash(const char *const aString, const uint32_t val = defaultOffset) noexcept
{
return (aString[0] == '[=10=]') ? val : hash(&aString[1], (val ^ uint32_t(aString[0])) * prime);
}
constexpr bool operator==(const HashedString & hs) const { return mHash == hs.mHash; }
constexpr bool operator==(const size_t & h) const { return mHash == h; }
constexpr bool operator!=(const HashedString & hs) const { return mHash != hs.mHash; }
constexpr bool operator!=(const size_t & h) const { return mHash != h; }
constexpr bool operator<(const HashedString & hs) const { return mHash < hs.mHash; }
private:
const size_t mHash = 0;
#if defined(_DEBUG)
const char* mString = nullptr;
#endif
};
static_assert(HashedString("FNV Hash Test") == 0xF38B3DB9, "HashedString of 'FNV Hash Test' shoulb be equal to 0xF38B3DB9");
int main(int , char**) {
constexpr HashedString hs("FNV Hash Test");
return hs == 0xF38B3DB9;
}
所以我的问题是:有没有办法让 visual studio 在编译时计算我的 constexpr
?
将 main 更改为:
constexpr auto hash = HashedString::hash("FNV Hash Test");
return hash == 0xF38B3DB9;
或
constexpr HashedString hs("FNV Hash Test");
constexpr auto answer = hs == 0xF38B3DB9;
return answer;
将导致在编译时计算散列。您的代码的方式不需要编译器在编译时计算哈希。通过要求编译器初始化一个 constexpr 变量,它被迫在编译时计算值。将 main 的代码减少为:
mov eax,1
ret
哇哦!用于 VS2015 的 SSA 优化。