Sim*_*ple 10 c++ arrays const constexpr c++11
为什么与数组一起使用const和constexpr使用时有区别?
int const xs[]{1, 2, 3};
constexpr int ys[]{1, 2, 3};
int as[xs[0]]; // error.
int bs[ys[0]]; // fine.
Run Code Online (Sandbox Code Playgroud)
我希望既xs[0]和ys[0]是常数表达式,但只有后者被视为这样.
作为社区维基的更长时间的评论.
表达式xs[0]在[expr.sub]/1中定义为*((xs)+(0)).(参见下面的parantheses.)
其中一个表达式应具有"指向
T" 的类型,另一个表达式应具有未映射的枚举或整数类型.
因此,应用了数组到指针的转换[conv.array]:
可以将"数组
N T"或"未知范围的数组" 类型的左值或右值T转换为"指向T" 的类型的prvalue .结果是指向数组的第一个元素的指针.
注意它可以在左值上运行,结果是一个prvalue,0因为整数文字也是一个prvalue.添加在[expr.add]/5中定义.由于两者都是prvalues,因此不需要左值到右值的转换.
int arr[3];
constexpr int* p = arr; // allowed and compiles
Run Code Online (Sandbox Code Playgroud)
现在关键的一步似乎是间接*[expr.unary.op]/1
一元运算
*符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式指向的对象或函数的左值.
因此,结果xs[0]是左值引用xs数组的第一个元素,并且是类型int const.
NB [expr.prim.general]/6
带括号的表达式是一个主表达式,其类型和值与所包含表达式的类型和值相同.括号的存在不会影响表达式是否为左值.
如果我们现在查看[expr.const]/2中不允许某些表达式和转换出现在常量表达式中的项目符号,那么可以应用的唯一项目符号(AFAIK)是左值到右值的转换:
除非适用,否则左值到右值的转换(4.1)
整数或枚举类型的非易失性glvalue,它引用具有前面初始化的非易失性const对象,用常量表达式初始化[注意:字符串文字(2.14.5)对应于此类对象的数组. - 注意],或
文字类型的非易失性glvalue,指的是用
constexpr这样的对象的子对象定义的非易失性对象,或者[...]
但是,在评估中出现的唯一真正的左值到右值转换(按照4.1(不是4.2,即数组到指针)xs[0]是从引用第一个元素的结果左值的转换.
对于OP中的示例:
int const xs[]{1, 2, 3};
int as[xs[0]]; // error.
Run Code Online (Sandbox Code Playgroud)
该元素xs[0]具有非易失性const整数类型,其初始化在其出现的常量表达式之前,并且已使用常量表达式初始化.
顺便说一句,在[expr.const]/2的引用段落中添加了"注释",以澄清这是合法的:
constexpr char c = "hello"[0];
Run Code Online (Sandbox Code Playgroud)
请注意,字符串文字也是左值.
如果有人(可以改变这个)解释为什么xs[0]不允许出现在常量表达式中,那将会很棒.