Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test if constexpr is evaluated correctly

I have used constexpr to calculate hash codes in compile times. Code compiles correctly, runs correctly. But I dont know, if hash values are compile time or run time. If I trace code in runtime, I dont do into constexpr functions. But, those are not traced even for runtime values (calculate hash for runtime generated string - same methods). I have tried to look into dissassembly, but I quite dont understand it

For debug purposes, my hash code is only string length, using this:

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

I have ID class created like this

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

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

}

If I do this in program main method

StringID id("hello world"); 

I got this disassembled code (part of it - there is a lot of more from inlined methods and other stuff in 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

How can I tell from this, that "hash value" is a compile time. I don´t see any constant like 11 moved to register. I am not quite good with ASM, so maybe it is correct, but I am not sure what to check or how to be sure, that "hash code" values are compile time and not computed in runtime from this code.

(I am using Visual Studio 2013 + Intel C++ 15 Compiler - VS Compiler is not supporting constexpr)

Edit:

If I change my code and do this

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

    mov       DWORD PTR [-24+ebp], 11                       ;55.15

I have got the correct result

Even with this

change private hashID to public

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

 printf("%i", id.hashID);
  // some other ASM code

But If I use private hashID and add Getter

  inline uint32 GetHashID() const { return this->hashID; };

to ID class, then I got

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

  printf("%i", id.GetHashID());
  // some other ASM code
like image 458
Martin Perry Avatar asked Mar 11 '15 13:03

Martin Perry


People also ask

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Are constexpr evaluated at compile time?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

Does constexpr improve performance?

Understanding constexpr Specifier in C++ constexpr is a feature added in C++ 11. The main idea is a performance improvement of programs by doing computations at compile time rather than run time. Note that once a program is compiled and finalized by the developer, it is run multiple times by users.


1 Answers

The most convenient way is to use your constexpr in a static_assert statement. The code will not compile when it is not evaluated during compile time and the static_assert expression will give you no overhead during runtime (and no unnecessary generated code like with a template solution).

Example:

static_assert(_StringLength("meow") == 4, "The length should be 4!");

This also checks whether your function is computing the result correctly or not.

like image 178
Otomo Avatar answered Oct 17 '22 08:10

Otomo