Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `std::is_constant_evaluated()` false for this constant-initialized variable?

Note 2 to [expr.const]/2 implies that if we have a variable o such that:

the full-expression of its initialization is a constant expression when interpreted as a constant-expression, except that if o is an object, that full-expression may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types

then:

Within this evaluation, std​::​is_­constant_­evaluated() [...] returns true.

Consider:

#include <type_traits>
int main() {
    int x = std::is_constant_evaluated();
    return x;
}

This program returns 0 when executed.

However, I don't see how the full-expression of the initialization of x is not a constant expression. I do not see anything in [expr.const] that bans it. Therefore, my understanding of the note (which is probably wrong) implies that the program should return 1.

Now, if we look at the normative definition of std::is_constant_evaluated, it is only true in a context that is "manifestly constant-evaluated", and the normative definition of the latter, [expr.const]/14, is more clear that the program above should return 0. Specifically, the only item that we really need to look at is the fifth one:

the initializer of a variable that is usable in constant expressions or has constant initialization ...

x is not usable in constant expressions, and it doesn't have constant initialization because no automatic variable does.

So there are two possibilities here. The more likely one is that I haven't understood the note, and I need someone to explain to me why the note does not imply that the program should return 1. The less likely one is that the note contradicts the normative wording.

like image 319
Brian Bi Avatar asked Sep 16 '21 22:09

Brian Bi


People also ask

Is Constexpr evaluated?

If you pass a non-constexpr argument to the PlusOne function, the compiler can't evaluate it at compile-time, and it will simply be a normal run-time function. Hint: "The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time."

Can constant be initialized?

A constant variable must be initialized at its declaration. To declare a constant variable in C++, the keyword const is written before the variable's data type. Constant variables can be declared for any data types, such as int , double , char , or string .


Video Answer


1 Answers

The full quote here is

A variable or temporary object o is constant-initialized if

  • (2.1) either it has an initializer or its default-initialization results in some initialization being performed, and
  • (2.2) the full-expression of its initialization is a constant expression when interpreted as a constant-expression, except that if o is an object, that full-expression may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types. [Note 2: Such a class can have a non-trivial destructor. Within this evaluation, std​::​is_­constant_­evaluated() ([meta.const.eval]) returns true. — end note]

The tricky bit here is that the term "is constant-initialized" (note: not "has constant initialization") doesn't mean anything by itself (it probably should renamed to something else). It's used in exactly three other places, two of which I'll quote below, and the last one ([dcl.constexpr]/6) isn't really relevant.

[expr.const]/4:

A constant-initialized potentially-constant variable V is usable in constant expressions at a point P if V's initializing declaration D is reachable from P and [...].

[basic.start.static]/2:

Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized ([expr.const]).

Let's replace "constant-initialized" with something less confusing, like "green".

So

  • A green potentially-constant variable is usable in constant expressions if [some conditions are met]
  • Constant initialization is performed if a variable or temporary object with static or thread storage duration is green.

Outside of these two cases, the greenness of a variable doesn't matter. You can still compute whether it is green, but that property has no effect. It's an academic exercise.

Now go back to the definition of greenness, which says that a variable or temporary object is green if (among other things) "the full-expression of its initialization is a constant expression when interpreted as a constant-expression" with some exceptions. And the note says that during this hypothetical evaluation to determine the green-ness of the variable, is_constant_evaluated() returns true - which is entirely correct.

So going back to your example:

int main() {
    int x = std::is_constant_evaluated();
    return x;
}

Is x green? Sure, it is. But it doesn't matter. Nothing cares about its greenness, since x is neither static nor thread local nor potentially-constant. And the hypothetical computation done to determine whether x is green has nothing to do with how it is actually initialized, which is governed by other things in the standard.

like image 199
T.C. Avatar answered Oct 25 '22 06:10

T.C.