Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Computing length of a C string at compile time. Is this really a constexpr?

I'm trying to compute the length of a string literal at compile time. To do so I'm using following code:

#include <cstdio>  int constexpr length(const char* str) {     return *str ? 1 + length(str + 1) : 0; }  int main() {     printf("%d %d", length("abcd"), length("abcdefgh")); } 

Everything works as expected, the program prints 4 and 8. The assembly code generated by clang shows that the results are computed at compile time:

0x100000f5e:  leaq   0x35(%rip), %rdi          ; "%d %d" 0x100000f65:  movl   $0x4, %esi 0x100000f6a:  movl   $0x8, %edx 0x100000f6f:  xorl   %eax, %eax 0x100000f71:  callq  0x100000f7a               ; symbol stub for: printf 

My question: is it guaranteed by the standard that length function will be evaluated compile time?

If this is true the door for compile time string literals computations just opened for me... for example I can compute hashes at compile time and many more...

like image 430
Mircea Ispas Avatar asked Sep 17 '14 12:09

Mircea Ispas


People also ask

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.

Is strlen a constexpr?

GCC (and other compilers) treat strlen as a 'constexpr' function as an extension to the language.

Can a string be constexpr?

constexpr std::string While it's best to rely on string_views and not create unnecessary string copies, the example above shows that you can even create pass vectors of strings inside a constexpr function!

What is the point of constexpr?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.


1 Answers

Constant expressions are not guaranteed to be evaluated at compile time, we only have a non-normative quote from draft C++ standard section 5.19 Constant expressions that says this though:

[...]>[ Note: Constant expressions can be evaluated during translation.—end note ]

You can assign the result to constexpr variable to be sure it is evaluated at compile time, we can see this from Bjarne Stroustrup's C++11 reference which says (emphasis mine):

In addition to be able to evaluate expressions at compile time, we want to be able to require expressions to be evaluated at compile time; constexpr in front of a variable definition does that (and implies const):

For example:

constexpr int len1 = length("abcd") ; 

Bjarne Stroustrup gives a summary of when we can assure compile time evaluation in this isocpp blog entry and says:

[...]The correct answer - as stated by Herb - is that according to the standard a constexpr function may be evaluated at compiler time or run time unless it is used as a constant expression, in which case it must be evaluated at compile-time. To guarantee compile-time evaluation, we must either use it where a constant expression is required (e.g., as an array bound or as a case label) or use it to initialize a constexpr. I would hope that no self-respecting compiler would miss the optimization opportunity to do what I originally said: "A constexpr function is evaluated at compile time if all its arguments are constant expressions."

So this outlines two cases where it should be evaluated at compile time:

  1. Use it where a constant expression is required, this would seem to be anywhere in the draft standard where the phrase shall be ... converted constant expression or shall be ... constant expression is used, such as an array bound.
  2. Use it to initialize a constexpr as I outline above.
like image 71
Shafik Yaghmour Avatar answered Oct 05 '22 08:10

Shafik Yaghmour