【问题标题】:Reference initialization and constant expressions引用初始化和常量表达式
【发布时间】:2017-12-20 17:00:05
【问题描述】:

作为this question 的后续,gcc 和 clang 都认为这个程序格式不正确:

int main() {
    const int& ri = 0;
    constexpr int i = ri;
}

错误是关于 ri 的值在常量表达式中不可用。 0 肯定是一个核心常量表达式,并且作为prvalue 核心常量表达式似乎满足these constraints(很简单,因为int 不是类、指针或数组类型)。那么ri不应该满足this criteria吗?

如果我使用类类型的纯右值文字也是如此:

struct X { };
int main() {
    const X& rx = X{};
    constexpr X x = rx;
}

【问题讨论】:

  • 一个对象不能同时属于类、指针和数组类型。没有一个对象可以满足所有的约束。它必须满足适当的要求。 int 类型的对象都不满足。所以不,ri 不适用。
  • 哦。感谢您让我意识到我误读了[expr.const]/6。它应该读取“具有静态存储持续时间的对象(不是临时对象或值满足上述约束的临时对象)”,而不是“(具有静态存储持续时间的对象不是临时对象)或(是一个临时对象,其值满足上述约束)”。
  • @StoryTeller 约束P -> Q 满足!P
  • @Barry - 我读它更像P1 || P2 || P3。在这种情况下,这三个都是相互排斥的。
  • 引用被初始化为应用到右值0调整为类型const int的临时实现转换的glvalue结果。您不能忽略转换而只考虑初始化程序的语法形式。

标签: c++ language-lawyer c++17


【解决方案1】:

在此声明中:

const int& ri = 0;

0 是一个纯右值,但ri 不是从该纯右值初始化的。 prvalue首先经历temporary materialization conversion,并且引用绑定到生成的glvalue。由于ri 绑定到这个物化的glvalue,而不是像你(我)怀疑的那样直接绑定到prvalue,因此相关限制不是prvalue 核心常量表达式限制(0 确实满足),而是glvalue 核心常量表达式限制 - 实体是permitted result of a constant expression。这个限制,拼写的清晰度略有提高,是:

具有静态存储持续时间的对象是:

  • 不是临时对象,或者
  • 一个临时对象,其值满足上述约束,

或者它是一个函数。

我们的glvalue 一个临时对象,它的值满足“上述约束”(“above”这里指的是prvalue核心常量限制,int很容易满足),但它确实没有静态存储持续时间。

没有静态存储持续时间→实体不是常量表达式的允许结果→glvalue表达式不是常量表达式→ri没有用常量表达式初始化→ri不能用于核心常量表达式 → i 的声明格式不正确。

同样的论点也适用于适当的类类型。

【讨论】:

  • 临时有静态存储持续时间是什么意思?
【解决方案2】:

正如您所指出的,2.11 规定 核心常量表达式 不得评估为:

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

    • 用常量表达式初始化或

还有 expr.const#6:

常量表达式要么是左值核心常量表达式 指的是一个实体,它是一个常量的允许结果 表达式(定义如下),或纯右值核心常量表达式 其值满足以下约束:

...

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

从我的阅读来看,这意味着const X& r =的RHS(用X代替某种类型)必须是具有静态存储持续时间的对象满足上述条件的临时对象.由于int 不适合类类型、指针类型或类/数组类型的对象,因此它不符合条件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多