10

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.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 1
    You're missing the required `#include `. – Keith Thompson Sep 16 '21 at 23:22
  • 3
    @KeithThompson Thank you for the correction. You're an experienced SO member, so I'm surprised you didn't edit the question yourself. – Brian Bi Sep 16 '21 at 23:37
  • If you read that https://en.cppreference.com/w/cpp/types/is_constant_evaluated, then it is clear from the example in that page that your code should get 0. – Phil1970 Sep 16 '21 at 23:37
  • @Phil1970 That doesn't answer my question. I want to understand whether a particular note in the standard is wrong. – Brian Bi Sep 16 '21 at 23:38
  • 2
    @BrianBi I thought about it, but I'm reluctant to edit code (other than simple formatting fixes). – Keith Thompson Sep 17 '21 at 00:24
  • 1
    In the *hypothetical* evaluation of the full-expression of the initialization "when interpreted as a *constant-expression*", `is_constant_evaluated` returns `true`. But this hypothetical evaluation isn't actually used anywhere. – T.C. Sep 17 '21 at 14:53
  • Hi Brian. Can you answer [this question](https://stackoverflow.com/q/73760274/19495502) if possible? – mada Sep 18 '22 at 17:09

1 Answers1

9

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • It might be worth explaining why `x` isn’t potentially constant: it’s not const-qualified. – Davis Herring Sep 17 '21 at 23:30
  • I see. Your explanation makes perfect sense. It seems that I was reading "within this evaluation ..." to mean "within the evaluation of the initialization of a variable that is constant-initialized" (assuming that point 2.2 is actually true, rather than 2.1 alone). But "this" refers only to the trial evaluation. I feel like the note could be made clearer, but at the same time, I also struggle to understand exactly why I didn't understand it in the first place. – Brian Bi Sep 18 '21 at 00:08