引用初始化和常量表达式
Reference initialization and constant expressions
作为这个问题的后续,gcc 和 clang 都认为这个程序格式不正确:
int main() {
const int& ri = 0;
constexpr int i = ri;
}
错误是关于ri
的值在常量表达式中不可用。0
当然是一个核心常量表达式,作为一个 prvalue 核心常量表达式似乎满足这些约束(很简单,因为int
不是类、指针或数组类型)。那么ri
不应该满足这个标准吗?
如果我使用类类型的 prvalue 文字,情况也是如此:
struct X { };
int main() {
const X& rx = X{};
constexpr X x = rx;
}
在此语句中:
const int& ri = 0;
0
是一个 prvalue,但ri
不是从该 prvalue 初始化的。prvalue 首先经历临时具体化转换,引用绑定到生成的 glvalue。由于ri
绑定到这个物化的glvalue,而不是像你(I)怀疑的那样直接绑定到prvalue,因此相关的限制不是prvalue核心常量表达式限制(0
确实满足),而是glvalue核心常量表达式限制 - 实体是常量表达式的允许结果。该限制的拼写清晰度略有提高,是:
静态存储持续时间为以下对象的任一对象:
- 不是临时对象,或
- 其值满足上述约束的临时对象,
或者它是一个函数。
我们的glvalue是一个临时对象,其值满足"上述约束"(这里的"以上"是指prvalue核心常量限制,int
微不足道地满足),但它没有静态存储持续时间。
没有静态存储持续时间 →实体不是常量表达式的允许结果 → glvalue 表达式不是常量表达式 →ri
未使用常量表达式初始化→ri
不能在核心常量表达式中使用→i
声明格式不正确。
同样的参数也适用于适当的类类型。
正如你所指出的,2.11 指出核心常量表达式的计算结果不得为:
引用
引用类型的变量或数据成员的 ID 表达式,除非引用具有前面的初始化和 也
- 它使用常量表达式或
进一步的expr.const#6:
常量表达式是 glvalue 核心常量表达式 指作为常量允许结果的实体 表达式(定义如下)或 prvalue 核心常量表达式 其值满足以下约束:
。
实体是常量表达式的允许结果,如果它是 具有非临时静态存储持续时间的对象 对象或 是其值满足上述条件的临时对象 约束,或者它是一个函数。
从我对此的解读来看,这意味着const X& r =
的 RHS(用 X 代替某种类型)必须是具有静态存储持续时间的对象或满足上述标准的临时对象。由于int
不适合类类型的对象、指针类型或类/数组类型,因此它不符合条件。
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 使用自动推导的 lambda 参数作为常量表达式
- 生成提升::hana::set 的常量表达式问题
- 为什么不能用常量表达式声明数组?
- 不是 lambda 函数中的常量表达式
- 函数调用在常量表达式中必须具有常量值
- 错误:constexpr 变量'struct2Var'必须由常量表达式初始化
- 如何在常量计算表达式中获取编译时错误?
- 关于在需要常量表达式的上下文中使用的glvalue常量表达式的问题
- 生成 constexpr 字符串表,不能产生常量表达式
- 整体模板参数。错误:在常量表达式中使用'this'
- 如何在满足常量表达式的同时将整数传递给指针,传递给 std::array<double、integer>?
- 编译器错误:函数调用在常量表达式中必须有一个常量值
- 错误:'new'不能出现在常量表达式中
- 我可以写出小于 -0.5 两个 ulps 的常量表达式双精度吗?
- 编译器在传递 const 变量时返回错误:模板参数不是常量表达式
- 为什么我不能在非常量表达式上使用此模板阶乘函数?
- C++ 使用变量而不是常量表达式初始化数组