C++ constexpr function in return statement

  • A+
Category:Languages

Why is a constexpr function no evaluated at compile time but in runtime in the return statement of main function?

It tried

template<int x> constexpr int fac() {     return fac<x - 1>() * x;  }   template<> constexpr int fac<1>() {     return 1;  }   int main() {     const int x = fac<3>();     return x; }  

and the result is

main:         push    rbp         mov     rbp, rsp         mov     DWORD PTR [rbp-4], 6         mov     eax, 6         pop     rbp         ret 

with gcc 8.2. But when I call the function in the return statement

template<int x> constexpr int fac() {     return fac<x - 1>() * x;  }   template<> constexpr int fac<1>() {     return 1;  }   int main() {     return fac<3>(); }  

I get

int fac<1>():         push    rbp         mov     rbp, rsp         mov     eax, 1         pop     rbp         ret main:         push    rbp         mov     rbp, rsp         call    int fac<3>()         nop         pop     rbp         ret int fac<2>():         push    rbp         mov     rbp, rsp         call    int fac<1>()         add     eax, eax         pop     rbp         ret int fac<3>():         push    rbp         mov     rbp, rsp         call    int fac<2>()         mov     edx, eax         mov     eax, edx         add     eax, eax         add     eax, edx         pop     rbp         ret 

Why is the first code evaluated at compile time and the second at runtime?

Also I tried both snippets with clang 7.0.0 and they are evaluated at runtime. Why is this not valid constexpr for clang?

All evaluation was done in godbolt compiler explorer.

 


A common misconception with regard to constexpr is that it means "this will be evaluated at compile time"1.

It is not. constexpr was introduced to let us write natural code that may produce constant expressions in contexts that need them. It means "this must be evaluatable at compile time", which is what the compiler will check.

So if you wrote a constexpr function returning an int, you can use it to calculate a template argument, an initializer for a constexpr variable (also const if it's an integral type) or an array size. You can use the function to obtain natural, declarative, readable code instead of the old meta-programming tricks one needed to resort to in the past.

But a constexpr function is still a regular function. The constexpr specifier doesn't mean a compiler has2 to optimize it to heck and do constant folding at compile time. It's best not to confuse it for such a hint.


1 - Thanks user463035818 for the phrasing.
2 - and consteval is a different story however :)

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: