confusion about constexpr function body

310 views Asked by At

cppreference said the following about the body of a constexpr function:

the function body must not contain:

  • a definition of a variable of non-literal type
  • a definition of a variable of static or thread storage duration.

All I understood about a constexpr function is that the statements in its body should be evaluated at compile-time so that the call expression can be evaluated at compile-time. Am I true?

Since C++14, the standard allows the body to contain variable definitions of literal types. So what about those definitions, are they evaluated at compile-time or runtime? since non-constexpr variables are allowed also.

What I think I misunderstood is that the compiler shall be able to evaluate at compile-time every statement in a constexpr function body. Does this true since C++14?

To make my confusion clear, I have this simple example:

// assuming std::is_literal_type<T> is true.
constexpr T f() { T t{}; return t; }; 

I can't understand how the compile behaves with the above snippet. Variable t is an automatic non-const variable and gets defined at run-time not compile-time; so it basically cannot appear in a constexpr declaration. Does this means, the compiler will never evaluate f() at compile-time because it has a statement, that's T t;, which will be evaluated at runtime only.

My confusion is increased when I have tried:

constexpr T result = f();

and it compiles successfully!. Does this mean f() are evaluated at compile-time? if yes, what about the runtime definition of t?

My second question is about why static-duration variables are not allowed in the body of a constexpr function.

1

There are 1 answers

4
Cubbi On

the statements in its body should be evaluated at compile-time

...along at least one possible code path.

Or, as the cpprefenrce page you're quoting puts it,

there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression

The function can be doing disk I/O if it wants to, as long as there is an if branch that skips it.

Variable t is ... defined at run-time not compile-time

It's defined in both. There is a run-time definition of the function (actual machine code compiled and written to the object file) and also there is a compile-time version of the function, a bunch of AST nodes or some sort of internal compiler representation of them. In a constexpr context, compile-time version will be evaluated and replaced by its result. In runtime context, a function call instruction will be compiled.