b1s*_*sub 13 c++ language-lawyer c++17
b
此代码中的表达式应为核心常量表达式
int main()
{
constexpr int a = 10;
const int &b = a;
constexpr int c = b; // here
return 0;
}
Run Code Online (Sandbox Code Playgroud)
由于标准说(8.20,第2段[expr.const]在N4700)
表达式
e
是核心常量表达式,除非评估e
将评估以下表达式之一:
...
除非适用,否则左值 - 右值转换(7.1)
...
非易失性glvalue,引用constexpr定义的非易失性对象,或引用此类对象的不可变子对象,或者
首先,b
上面代码中的表达式是一个左值(也是一个glvalue),因为它是一个引用,因此是一个变量(8.1.4.1,第1段[expr.prim.id.unqual]):
如果实体是函数,变量或数据成员,则表达式是左值 ,否则为prvalue; 如果标识符指定位字段(11.5),则它是位字段.
其次,变量b
表示的对象是a
,并且声明了它constexpr
.但是,gcc抱怨道
./hello.cpp: In function ‘int main()’:
./hello.cpp:6:20: error: the value of ‘b’ is not usable in a constant expression
constexpr int c = b;
^
./hello.cpp:5:13: note: ‘b’ was not declared ‘constexpr’
const int &b = a;
Run Code Online (Sandbox Code Playgroud)
据我所知,引用不是一个对象,所以上面的子弹显然表明a
应该声明constexpr
.我错过了什么吗?我不同意gcc的原因是gcc将其b
视为一个对象,因此需要将其声明为constexpr
.但是,b
不是一个对象!
Bar*_*rry 13
核心常量表达式的一个规则是我们无法评估:
一个id-expression,引用引用类型的变量或数据成员,除非引用具有先前的初始化和任何一个
- 它是用常量表达式初始化的
- 它的生命始于e的评价范围内;
b
是一个id-expression,它引用具有前面初始化的引用类型的变量.但是,它是从初始化a
.是a
一个不变的表达?来自[expr.const]/6:
甲常量表达式可以是一个glvalue芯常量表达式指的是一个常量表达式的结果允许的实体(如下面所定义),或一个prvalue芯常数表达式,其值满足以下约束条件:[...]
如果实体是具有静态存储持续时间的对象,则该实体是常量表达式的允许结果,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是函数.
a
是glvalue核心常量表达式(它没有达到expr.const/2中的任何限制),但它不是具有静态存储持续时间的对象.它也不是一种功能.
因此,a
不是一个恒定的表达.并且b
,作为结果,不从常量表达式初始化,并且因此不能在核心常量表达式被使用.因此c
,初始化是不正确的,因为它不是一个恒定的表达式.声明a
为a static constexpr int
,gcc和clang都接受该程序.
C++,你是神奇的野兽.