为什么这个常量初始化变量的 std::is_constant_evaluated() 为假?

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

[expr.const]/2 的注释 2 意味着如果我们有一个变量 o 这样:

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

然后:

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

考虑:

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

这个节目returns 0 when executed.

但是,我没有看到 x 初始化的完整表达式不是常量表达式。我在 [expr.const] 中没有看到任何禁止它的内容。因此,我对注释的理解(这可能是错误的)意味着程序应该 return 1.

现在,如果我们查看 std::is_constant_evaluated 的规范定义,它仅在“明显恒定评估”的上下文中才成立,而后者的规范定义 [expr.const]/14 , 更清楚的是上面的程序应该 return 0。具体来说,我们真正需要看的唯一项目是第五个:

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

x 在常量表达式中不可用,并且它没有常量初始化,因为没有自动变量。

所以这里有两种可能。更有可能的是我没看懂注释,我需要有人向我解释为什么注释 而不是 暗示程序应该 return 1. The不太可能的是注释与规范措辞相矛盾。

这里的完整引述是

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]

这里的棘手之处在于术语“常量初始化”(注意:不是“具有常量初始化”)本身并不意味着什么(它可能应该重命名为其他名称)。它恰好用在其他三个地方,其中两个我将在下面引用,最后一个 ([dcl.constexpr]/6) 并不是真正相关的。

[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]).

让我们将“constant-initialized”替换为不那么令人困惑的东西,例如“green”。

所以

  • 如果[满足某些条件]
  • ,绿色的潜在常量变量可用于常量表达式
  • 如果具有静态或线程存储持续时间的变量或临时对象为绿色,则执行常量初始化。

除了这两种情况,变量的绿色并不重要。您仍然可以计算它是否为绿色,但 属性 无效。这是一个学术练习。

现在回到绿色的定义,它说变量或临时对象是绿色的,如果(除其他外)“其初始化的完整表达式在解释为 constant-expression”,但有一些例外。注释说,在这个确定变量绿色度的假设评估中,is_constant_evaluated() returns true - 这是完全正确的。

所以回到你的例子:

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

x是绿色的吗?当然是啦。不过没关系。没有人关心它的绿色,因为 x 既不是静态的,也不是线程局部的,也不是潜在的常量。确定 x 是否为绿色的假设计算与它的实际初始化方式无关,这取决于标准中的其他内容。