首页 > 解决方案 > 为什么用 constexpr 声明的引用可以绑定到 Indeterminate 值变量?

问题描述

int aaa;
int& v = aaa;
int& rf = v;
constexpr int& crf = rf;
int main(){
}

我想知道为什么所有编译器都同意这个例子是格式正确的?constexpr 变量不应该具有在编译器期间可以知道的值吗?既然 的值aaa有一个 Indeterminate 值,为什么这个例子能被编译器接受呢?

标签: c++language-lawyer

解决方案


对于这个例子,在我看来,这相当于问为什么rf可以在常量表达式中使用变量。根据 [dcl.constexpr#10],初始化的完整表达式crf应该是一个常量表达式。根据 [expr.const#11]

常量表达式要么是泛指值核心常量表达式,它引用作为常量表达式(如下定义)的允许结果的实体,要么是其值满足以下约束的纯右值核心常量表达式

如果实体是具有静态存储持续时间的对象,该对象不是临时对象或者是其值满足上述约束的临时对象,或者如果它是非立即函数,则该实体是常量表达式的允许结果。

在这种情况下,由于引用绑定应该绑定到一个glvalue,因此rf应该是一个glvalue核心常量表达式;由于rf是指aaa具有静态存储时长的对象,因此我们只需要检查是否rf是核心常量表达式,由[expr.const#5]决定。由于rf是引用类型的 id 表达式,因此它应满足 [expr.const#5.12]

一个 id 表达式,它引用引用类型的变量或数据成员,除非引用具有前面的初始化并且

  • 它可用于常量表达式或
  • 它的生命周期始于对 E 的评估;

这里它必须满足它可以在一个常量表达式中使用,它由 [expr.const#4] 确定

如果 V 的初始化声明 D 可以从 P 和

  • V 是 constexpr,
  • V 未初始化为 TU 本地值,或
  • P 与 D 在同一个翻译单元中。

一个对象或引用可以在常量表达式中使用,如果它是

  • 可用于常量表达式的变量,或

由于rf是参考,因此由于 [expr.const#3] 它可能是恒定的

如果变量是 constexpr 或者它具有引用或 const 限定的整数或枚举类型,则该变量可能是常量。

是否为常量初始化由[expr.const#2]决定

变量或临时对象 o 是常量初始化的,如果

  • [2.1] 要么它有一个初始化器,要么它的默认初始化导致一些初始化被执行,并且
  • [2.2] 当解释为常量表达式时,其初始化的完整表达式是常量表达式...

has an initializer的声明rf,bullet 2.1 为真,到目前为止,是否rf是一个常量表达式已经转向检查其初始化的完整表达式是否是一个常量表达式。同样,v应该是一个常量表达式;判断是否v为常量表达式的过程与rf上面给出的过程类似。进而判断初始化器aaa是否为常量表达式,我说是,因为aaa它是一个静态存储持续时间对象并且评估它不会违反[expr.const#5]中定义的任何规则,因此它是一个glvalue核心常量表达式. 因此,v可用于常量表达式,这意味着rf也可用于常量表达式。总之,初始化的全表达式crf就是一个常量表达式。

另外,无论rfv、 还是aaa,它们都被用作glvalue核心常量表达式,因此在本例中它的值并不重要。


推荐阅读