为什么用 constexpr 声明的引用可以绑定到不确定值变量?

Why can a reference declared with constexpr be bound to an Indeterminate value variable?

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

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

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

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints

An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.

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

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

  • it is usable in constant expressions or
  • its lifetime began within the evaluation of E;

这里必须满足在常量表达式中可用,由[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

  • V is constexpr,
  • V is not initialized to a TU-local value, or
  • P is in the same translation unit as D.

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

  • a variable that is usable in constant expressions, or

由于 rf 是参考,因此由于 [expr.const#3]

它可能是常数

A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.

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

决定

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...

rf的声明有一个初始化器,2.1条是正确的,目前rf是否是常量表达式已经转向检查其初始化的完整表达式是否为一个常量表达式。同样,v 应为常量表达式;判断v是否为常量表达式和上面rf的过程类似。反过来就是判断初始化器aaa是否是一个常量表达式,我说是,因为aaa是一个静态存储持续时间对象并且评估它不会违反[[=59=中定义的任何规则]#5],因此它是一个偏左值核心常量表达式。因此,v 可用于常量表达式,这意味着 rf 也可用于常量表达式。简而言之,crf初始化的完整表达式是一个常量表达式。

此外,无论rfvaaa,都是作为泛左值核心常量表达式,因此在这个例子中它的值并不重要。