为什么这个常量初始化变量的 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;
}
但是,我没有看到 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
是否为绿色的假设计算与它的实际初始化方式无关,这取决于标准中的其他内容。
[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 foro
and its subobjects even if those objects are of non-literal class types
然后:
Within this evaluation,
std::is_constant_evaluated()
[...] returnstrue
.
考虑:
#include <type_traits>
int main() {
int x = std::is_constant_evaluated();
return x;
}
但是,我没有看到 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 foro
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]) returnstrue
. — end note]
这里的棘手之处在于术语“常量初始化”(注意:不是“具有常量初始化”)本身并不意味着什么(它可能应该重命名为其他名称)。它恰好用在其他三个地方,其中两个我将在下面引用,最后一个 ([dcl.constexpr]/6) 并不是真正相关的。
[expr.const]/4:
A constant-initialized potentially-constant variable
V
is usable in constant expressions at a pointP
ifV
'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
是否为绿色的假设计算与它的实际初始化方式无关,这取决于标准中的其他内容。