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

Bri*_*ian 10 c++ language-lawyer c++20

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

\n
\n

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

\n
\n

then:

\n
\n

Within this evaluation, std\xe2\x80\x8b::\xe2\x80\x8bis_\xc2\xadconstant_\xc2\xadevaluated() [...] returns true.

\n
\n

Consider:

\n
#include <type_traits>\nint main() {\n    int x = std::is_constant_evaluated();\n    return x;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

This program returns 0 when executed.

\n

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.

\n

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:

\n
\n

可在常量表达式中使用或具有常量初始化的变量的初始值设定项...

\n
\n

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

\n

所以这里有两种可能性。更有可能的是我还没有理解这个注释,我需要有人向我解释为什么这个注释并不意味着程序应该返回1。不太可能的是这个注释与规范的措辞相矛盾。

\n

T.C*_*.C. 9

这里的完整报价是

\n
\n

变量或临时对象在以下情况下o被常量初始化:

\n
    \n
  • (2.1) 它有一个初始化器或者它的默认初始化导致执行一些初始化,并且
  • \n
  • (2.2) 当解释为常量表达式时,其初始化的完整表达式是常量表达式,除了 if\no是一个对象,该完整表达式还可以为其o及其子对象调用 constexpr\n 构造函数,即使这些对象是\n非文字类类型。[注 2:这样的类可以有一个重要的析构函数。在此评估中,\n std\xe2\x80\x8b::\xe2\x80\x8bis_\xc2\xadconstant_\xc2\xadevaluated()([meta.const.eval]) 返回true.\n\xe2\x80\x94尾注]
  • \n
\n
\n

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

\n

[expr.const]/4:

\n
\n

如果\ 的初始化声明 D 可从 P 和 [...] 到达,则常量初始化的潜在常量变量V可在常量表达式中使用。PV

\n
\n

[基本.启动.静态]/2:

\n
\n

如果具有静态或线程存储持续时间的变量或临时对象被常量初始化([expr.const]),则执行常量初始化。

\n
\n

让我们用一些不那么令人困惑的东西替换“常量初始化”,比如“绿色”。

\n

所以

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

除了这两种情况之外,变量的绿色程度并不重要。您仍然可以计算它是否是绿色的,但该属性不起作用。这是一项学术练习。

\n

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

\n

回到你的例子:

\n
int main() {\n    int x = std::is_constant_evaluated();\n    return x;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

是x绿色的吗?就是这样。但这并不重要。没有什么关心它的绿色度,因为它既x不是静态的,也不是线程局部的,也不是潜在恒定的。为确定是否为绿色而进行的假设计算x与它的实际初始化方式无关,它是由标准中的其他内容控制的。

\n