0

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.

mada
  • 1,646
  • 1
  • 15
  • "one post one question" ... but regarding your first one, templates are not runtime entities ... think of them as a copy-paste-per-T copies – OrenIshShalom Apr 20 '22 at 04:48
  • @OrenIshShalom, I am not said that `f` is template function!. – mada Apr 20 '22 at 04:51
  • 3
    "gets defined at run-time" no it is not. What makes you believe so? – n. m. could be an AI Apr 20 '22 at 04:51
  • Your function `f` returns a default constructed `T`. so in constant expression you directly have a default constructed `T` (at compile time). – Jarod42 Apr 20 '22 at 09:00
  • @Jarod42 - That's OK for me if `T` is a class type. But what if `T` is `int` for example, Is this mean that `t` will be defined at compile-time also? – mada Apr 20 '22 at 17:22
  • With `T=int`, t will have undetermined value, so won't compile in constant expression (when computing value at compile time), and will have UB when used at runtime (so invalid in constant expression). – Jarod42 Apr 20 '22 at 18:11
  • Thanks, @Jarod42 - But I think you left off the point I asked for. If `T=int` and `t` has determined value and the function call appears in a constant expression context. Does `t` get defined at compile time? I think now you got what I intended. – mada Apr 20 '22 at 19:55
  • 1
    For `constexpr int f42() { int res = 42; return res; };`, `std::cout << f42();` is computed at runtime whereas `constexpr int n = f42();` is computed at compile time. – Jarod42 Apr 21 '22 at 07:50
  • @Jarod42 - That's true. Does this mean that `res` is defined at compile-time? if yes, so why `constexpr int f42() { int res = 42; constexpr int other = res; return res; };` initialization of `other` is an error, and value of `res` is known at compile-time? – mada Apr 21 '22 at 17:03
  • Variable `res` cannot appear in a constant expression just because it's not const, not because it's defined at runtime. Variable `res` is defined at compile-time since it's constant-initialzied, but because `res` isn't declared as const nor constexpr, it cannot appear in a constant expression context. – mada Apr 21 '22 at 17:14

1 Answers1

0

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.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • I just need to confirm. If `T=int` and `t` has *determined value* and the function call appears in a constant expression context. Does `t` get defined at compile time? – mada Apr 20 '22 at 19:48
  • @marina Yes, [if you define t;](https://wandbox.org/permlink/zbo5orjMbvJkVyCC) As written, with t indeterminate, [it won't compile](https://wandbox.org/permlink/33oRxyWXv4aGcvth) – Cubbi Apr 20 '22 at 20:59
  • Yes how? and if `t` appears in a constant expression, the program [won't compile](https://wandbox.org/permlink/GaLhcgti3f8J5GHW). Am I conflating something here?. – mada Apr 20 '22 at 21:12
  • @marina Following the dual function mental model, it's the run-time version of `f` that fails to compile in your new example. But technically the code is just running afoul of constexpr variable rules, which don't care that the code is on the constexpr code path through a constexpr function. – Cubbi Apr 21 '22 at 02:11