我已经使用constexpr在编译时计算哈希码。代码正确编译,运行正确。但是我不知道,哈希值是编译时还是运行时。如果我在运行时跟踪代码,则不会执行constexpr函数。但是,即使对于运行时值也不会跟踪这些值(为运行时生成的字符串计算哈希-相同的方法)。我试图研究反汇编,但我不太了解]
出于调试目的,我的哈希码仅为字符串长度,使用此方法:
constexpr inline size_t StringLengthCExpr(const char * const str) noexcept
{
return (*str == 0) ? 0 : StringLengthCExpr(str + 1) + 1;
};
我有这样创建的ID类
class StringID
{
public:
constexpr StringID(const char * key);
private:
const unsigned int hashID;
}
constexpr inline StringID::StringID(const char * key)
: hashID(StringLengthCExpr(key))
{
}
如果我在程序main
方法中执行此操作
StringID id("hello world");
我得到了这个反汇编的代码(部分内容-内联方法和main中的其他内容有很多)
;;; StringID id("hello world");
lea eax, DWORD PTR [-76+ebp]
lea edx, DWORD PTR [id.14876.0]
mov edi, eax
mov esi, edx
mov ecx, 4
mov eax, ecx
shr ecx, 2
rep movsd
mov ecx, eax
and ecx, 3
rep movsb
// another code
我如何由此得知,“哈希值”是一个编译时间。我没有看到像11这样的常量移到寄存器中。我对ASM不太满意,所以也许它是正确的,但是我不确定要检查什么或如何确定“哈希代码”值是编译时的,而不是在运行时根据此代码计算的。
((我正在使用Visual Studio 2013 + Intel C ++ 15编译器-VS编译器不支持constexpr)
编辑:
如果我更改代码并执行此操作
const int ix = StringLengthCExpr("hello world");
mov DWORD PTR [-24+ebp], 11 ;55.15
我得到正确的结果
甚至与此
将私有hashID更改为public
StringID id("hello world");
// mov DWORD PTR [-24+ebp], 11 ;55.15
printf("%i", id.hashID);
// some other ASM code
但是,如果我使用私有hashID并添加Getter,则>]
inline uint32 GetHashID() const { return this->hashID; };
到ID班,然后我得到了
StringID id("hello world");
//see original "wrong" ASM code
printf("%i", id.GetHashID());
// some other ASM code
我已经使用constexpr在编译时计算哈希码。代码正确编译,运行正确。但是我不知道,哈希值是编译时还是运行时。如果我在运行时跟踪代码,则... ...>
最方便的方法是在constexpr
语句中使用static_assert
。如果在编译时未对其进行评估,则该代码将无法编译,并且static_assert
表达式将在运行时不给您任何开销(并且不会产生像模板解决方案那样的不必要的生成代码)。
示例:
如果要确保在编译时评估constexpr
函数,请在需要编译时评估的情况下使用其结果:
有几种方法可以强制进行编译时评估。但是这些功能不像使用constexpr
时所期望的那样灵活且易于设置。而且,它们不能帮助您确定是否实际使用了编译时常量。
以下技巧可以帮助检查constexpr函数是否仅在编译时进行了评估:
简单地将其放在constexpr变量中。
将来(c ++ 20),您可以使用consteval说明符来声明一个函数,该函数必须在编译时进行评估,因此需要constant expression上下文。