下面的代码不能在GCC 5.3.0下编译,因为声明r
缺少一个constexpr
说明符.
const int i = 1; const int& r = i; constexpr int j = r;
我相信拒绝是正确的.如何使用N4527工作草案证明这一点?
首先,由于我们使用的是引用,因此不得违反[expr.const] /(2.9).(2.9.1)适用,但:
一个id-expression,引用引用类型的变量或数据成员,除非引用具有先前的初始化,并且
- 或者使用常量表达式初始化
即使用r
很好,只要初始化器 - i
- 是一个常量表达式(如下所示).
还有必要检查第3行中的ltr转换是否合法,即不得违反(2.7).但是,(2.7.1)适用:
一个左值到右值的转换(4.1),除非它被应用于
- 一个非整数或枚举类型的非易失性glvalue,它引用一个完整的非易失性const
对象,具有前面的初始化,用一个常量表达式初始化,或者
......所以这很好,因为(g)左值是r
,它引用i
- 这是一个const
带有常量表达式初始化器(1
)的非易失性对象.
我们推迟显示i
实际上是一个常量表达式,一旦这样,我们需要表明它r
是一个常量表达式.
[expr.const]/5与此有关:
甲常量表达式可以是一个glvalue芯常量表达式,其值指的是一个常量表达式的一个允许的结果的实体(如下面所定义),或一个prvalue芯常量表达式,其值是一个对象,其中,该对象和它的子对象:
引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和
如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象的结尾的地址(5.7),函数的地址或空指针值.
如果实体是具有静态存储持续时间的对象,则该实体是常量表达式的允许结果,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是函数.
因为i
在上面的上下文中,(g)左值,它必须是常量表达式的允许结果 - 因为它具有静态存储持续时间并且当然不是临时的.因此i
是一个恒定的表达.
r
但是,它被视为第3行中的prvalue.由于我们已经确定这r
是一个核心常量表达式,我们只需要检查项目符号.但他们显然已经相遇了.
因此,代码在命名空间范围内格式良好.它不会在本地范围内,因为i
不再是常量表达式的允许结果.Clang给出了一个全面的错误消息.