const和constexpr数组之间的区别

时间:2013-08-09 11:21:14

标签: c++ arrays c++11 const constexpr

为什么在使用数组时constconstexpr之间存在差异?

int const xs[]{1, 2, 3};
constexpr int ys[]{1, 2, 3};

int as[xs[0]];  // error.
int bs[ys[0]];  // fine.

我希望xs[0]ys[0]都是常量表达式,但只有后者才会被视为。

2 个答案:

答案 0 :(得分:5)

作为社区维基的更长时间的评论。


表达式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

现在关键的一步似乎是间接* [expr.unary.op] / 1

  

一元*运算符执行间接:应用它的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用对象或函数的左值其中的表达点。

因此,xs[0]的结果是左值,引用xs数组的第一个元素,类型为int const


N.B。 [expr.prim.general] / 6

  

带括号的表达式是一个主表达式,其类型和值与所附表达式的类型和值相同。括号的存在不会影响表达式是否为左值。


如果我们现在查看[expr.const] / 2中不允许某些表达式和转换出现在常量表达式中的项目符号,可以应用的唯一项目符号(AFAIK)是左值到右值的转换:

  
      
  • 左值 - 右值转换(4.1),除非它适用于

         
        
    • 整数或枚举类型的非易失性glvalue,它引用具有前面初始化的非易失性const对象,用常量表达式初始化[注意:字符串文字(2.14.5)对应于数组这些物体。 - 尾注],或

    •   
    • 文字类型的非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用此类对象的子对象,或

    •   
  •   
     

[...]

但是xs[0]的评估中出现的唯一真正的左值(右)转换(不是4.2,即数组到指针)是从结果左值转换到第一个元素。

对于OP中的示例:

int const xs[]{1, 2, 3};
int as[xs[0]];  // error.

此元素xs[0]具有非易失性const整数类型,其初始化位于其出现的常量表达式之前,并且已使用常量表达式初始化。


顺便说一下,在[expr.const] / 2 has been added to clarify的引用段落中添加的“注释”,这是合法的:

constexpr char c = "hello"[0];

请注意,字符串文字也是左值。


如果有人(可以改变这一点)解释为什么不允许xs[0]出现在常量表达式中,那就太棒了。

答案 1 :(得分:0)

C ++ 11 constexpr用于在编译时评估表达式,与const关键字不同。

constexpr int ys[]{1, 2, 3};在编译时进行评估,因此没有错误

使用ys[0]时。

另外,请注意C ++ 11统一初始化与{}

一起使用

其他例子:

constexpr int multipletwo(int x)
{
return 2*x;
}

int num_array[multipletwo(3)]; //No error since C++11, num_array has 6 elements.