为什么在数组使用时 const
和 constexpr
会有区别?
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]
都被视为常量表达式,但只有后者被视为常量表达式。
一条较长的社区百科评论。
表达式xs [0]
在[expr.sub] / 1中定义为*((xs)+(0))
。 (请参见下面的括号。)
其中一个表达式应具有“指向
T
的指针”类型,另一个应具有未作用域的枚举或整数类型。
因此应用数组到指针转换[conv.array]:
“
N T
的数组”或“未知边界的T
的数组”的lvalue或rvalue可以转换为类型为“指向T
的指针”的prvalue。结果是数组的第一个元素的指针。
请注意它可以对lvalue进行操作,结果是一个prvalue,0
作为整数字面值也是一个prvalue。加法在[expr.add] / 5中定义。由于两个都是prvalues,因此不需要进行lvalue到rvalue的转换。
int arr[3];
constexpr int* p = arr; // allowed and compiles
*
[ expr.unary.op ] / 1*
执行间接引用:应用于其上的表达式应为指向对象类型或函数类型的指针,并且结果是指向表达式所指对象或函数的左值。因此,xs [0]
的结果是指向xs
数组的第一个元素的左值,类型为int const
。xs [0]
时出现的唯一真正的左值到右值转换是从指向第一个元素的结果左值转换而来。int const xs[]{1, 2, 3};
int as[xs[0]]; // error.
这个元素xs[0]
具有非易失性的const整型,它的初始化在出现常量表达式的前面,并且已经用一个常量表达式进行了初始化。
顺便提一句,在引用的[expr.const]/2段中添加的"注释"已被添加以澄清以下合法:
constexpr char c = "hello"[0];
xs[0]
,那就太好了。const int a = 0; int x[a];
)。C++03也不允许"foo"[0]
,但是这个段落也允许了它,这是草案后来的“让我们保持非规范性编辑”的变更,因为从字符串字面量中读取被认为是可取的。实际上,bullet1的真正意图似乎是“允许从字符串字面量中读取,并保持与C++03向后兼容”。 - Johannes Schaub - litbconst int a = 1; int x[a];
”。在C++11中不允许这样做将破坏向后兼容性。 - Johannes Schaub - litbC++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.
constexpr
值可以在编译时计算,而const
则不行。 - teh internets is made of catzconst
数组不需要有可见的定义(它可以是extern
或稍后在文件中定义),这就是为什么会有区别。至于为什么有这个区别,我怀疑标准本来可以规定:当一个定义存在且对于constexpr
是有效的(就像你代码中的情况一样),那么const
和constexpr
一样好,因为此时信息可用于评估它。我不知道为什么标准没有这么说,但是也许一个好理由是:"如果你想让你的数组是constexpr
,那就直接说吧"。 - Steve Jessopint const x = 5;
和constexpr int y = 5
都可以作为数组声明的固定大小 (int a[x], b[y]
),但在被不同对待的数组内部(这涉及到 Steve 上面的评论)。 - WhozCraigconstexpr
需要用其他constexpr
初始化,而const
数组则可以使用非constexpr
来初始化,比如一个函数f()
,const T array[] = { f(1), f(2), f(3) };
将是动态初始化,而不是静态(constexpr
)初始化。 - David Rodríguez - dribeasconstexpr
有效”的意思。就像你所说的,为了触发特殊处理,该定义需要能够作为constexpr
进行评估。 - Steve Jessop