c++ - 为什么用 constexpr 声明的引用可以绑定到 Indeterminate 值变量?
问题描述
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]
常量表达式要么是泛指值核心常量表达式,它引用作为常量表达式(如下定义)的允许结果的实体,要么是其值满足以下约束的纯右值核心常量表达式
如果实体是具有静态存储持续时间的对象,该对象不是临时对象或者是其值满足上述约束的临时对象,或者如果它是非立即函数,则该实体是常量表达式的允许结果。
在这种情况下,由于引用绑定应该绑定到一个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
就是一个常量表达式。
另外,无论rf
、v
、 还是aaa
,它们都被用作glvalue核心常量表达式,因此在本例中它的值并不重要。
推荐阅读
- google-drive-api - 如何将文件上传到用户谷歌驱动器帐户
- sql - 在 sqlite 中选择最大值的总和
- python - train_on_batch 和 gradientTape 之间的不同行为
- python - 使用 python 字典和 Lambda 函数
- java - 如何将一个实体映射到不同的表
- rest - 有哪些策略可以实现搜索功能以过滤掉应用程序(前端)中的数据?
- c++ - 用mingw g++编译简单的hello world
- python - 使用 dask 加载大型压缩数据集
- javascript - 如何使用正则表达式从字符串中提取所有 24 小时时间?
- azure - 如何将我的自定义属性传递到 Azure AD 应用程序中的重定向 url?