如何测试constexpr是否被正确评估

Mar*_*rry 8 c++ constexpr c++11

我使用constexpr在编译时计算哈希码.代码编译正确,运行正常.但我不知道,如果哈希值是编译时间或运行时间.如果我在运行时跟踪代码,我不会进入constexpr函数.但是,即使对于运行时值也不会跟踪它们(计算运行时生成的字符串的哈希值 - 相同的方法).我试图调查反汇编,但我完全不理解它

出于调试目的,我的哈希码只是字符串长度,使用:

constexpr inline size_t StringLengthCExpr(const char * const str) noexcept
{
    return (*str == 0) ? 0 : StringLengthCExpr(str + 1) + 1;
};
Run Code Online (Sandbox Code Playgroud)

我有像这样创建的ID类

class StringID
{
    public:
       constexpr StringID(const char * key);
    private:
       const unsigned int hashID;
}

constexpr inline StringID::StringID(const char * key)
        : hashID(StringLengthCExpr(key))
{

}
Run Code Online (Sandbox Code Playgroud)

如果我在程序main方法中这样做

StringID id("hello world"); 
Run Code Online (Sandbox Code Playgroud)

我得到了这个反汇编代码(它的一部分 - 内联方法和其他东西中有很多东西)

;;;     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
Run Code Online (Sandbox Code Playgroud)

我怎么能从中得知,"哈希值"是编译时间.我没有看到任何像11一样的常数注册.我对ASM不是很好,所以也许它是正确的,但我不确定要检查什么或如何确定,"哈希代码"值是编译时间而不是在运行时从此代码计算.

(我使用的是Visual Studio 2013 +英特尔C++ 15编译器 - VS编译器不支持constexpr)

编辑:

如果我更改我的代码并执行此操作

    const int ix = StringLengthCExpr("hello world");

    mov       DWORD PTR [-24+ebp], 11                       ;55.15
Run Code Online (Sandbox Code Playgroud)

我得到了正确的结果

即便如此

将私有hashID更改为public

 StringID id("hello world"); 
  // mov       DWORD PTR [-24+ebp], 11                       ;55.15

 printf("%i", id.hashID);
  // some other ASM code
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用私有hashID并添加Getter

  inline uint32 GetHashID() const { return this->hashID; };
Run Code Online (Sandbox Code Playgroud)

到ID班,然后我得到了

  StringID id("hello world"); 
  //see original "wrong" ASM code

  printf("%i", id.GetHashID());
  // some other ASM code
Run Code Online (Sandbox Code Playgroud)

Oto*_*omo 22

最方便的方法是constexprstatic_assert声明中使用您的.在编译期间未对代码进行求值时,代码将无法编译,并且static_assert表达式将在运行时期间不会产生任何开销(并且没有像模板解决方案那样的不必要的生成代码).

例:

static_assert(_StringLength("meow") == 4, "The length should be 4!");
Run Code Online (Sandbox Code Playgroud)

这还会检查您的函数是否正确计算结果.


Rei*_*ica 5

如果要确保constexpr在编译时评估函数,请将其结果用于需要编译时评估的内容:

template <size_t N>
struct ForceCompileTimeEvaluation { static constexpr size_t value = N; };

constexpr inline StringID::StringID(const char * key)
        : hashID(ForceCompileTimeEvaluation<StringLength(key)>::value)
{}
Run Code Online (Sandbox Code Playgroud)

请注意,我已将该功能重命名为just StringLength.以下划线后跟大写字母或包含两个连续下划线的名称在用户代码中不合法.它们是为实现保留的(编译器和标准库).

  • 但这将失去 constexpr 的优势,如果在编译时无法评估值(如 StringID(某些生成的变量)) (2认同)