下面的C++11程序是不是格式错误?
const int x[] = {1,2,3};
static_assert(x[0] == 1, "yay");
int main() {}
gcc和clang似乎是这么认为的,但是为什么x[0] == 1
不是一个恒定的表达呢?
x[0] == 1
subscript operator
*(x+0) == 1
array-to-pointer conversion (int* p = x)
*(p+0) == 1
pointer addition
*p == 1
indirection (lvalue y = x[0])
y == 1
lvalue-to-rvalue conversion:
非易失性glvalue (是的,x是glvalue且非易失性的)整数(是的,它具有const int类型)或枚举类型,引用具有先前初始化(是的,用1初始化)的非易失性const对象(是的,它具有const int类型),用常量表达式初始化(yes 1是常量表达式)
看起来是真的,x
数组的第一个元素满足这些条件。
1 == 1
这是一个编译器错误,标准缺陷,还是我遗漏了什么?
5.19 expr.const的哪个部分说这不是一个常量表达式?
发布于 2013-09-20 03:53:27
在5.19中:
...expression是一个常量表达式,除非它包含以下内容之一...:
- a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
- a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
- a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression
简单地说,左值到右值的转换只能在满足以下条件的常量表达式中完成:
使用常量expression...初始化的带有constant:const int x = 3;
.
constexpr int x[] = {1,2,3};
.
constexpr
您的示例确实包含了左值到右值的转换,但没有任何例外,因此x
不是常量表达式。但是,如果您将其更改为:
constexpr int x[] = {1,2,3};
static_assert(x[0] == 1, "yay");
int main() {}
那么一切都很好。
发布于 2013-09-20 19:39:07
根据标准的当前措辞,它是一个编译器错误,并且该程序是格式良好的。现在正在考虑它是否应该是一个标准缺陷,因为它将很难实现。
有关详细说明,请参阅:
https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/Nv5_2dCHm6M
报告复制如下:
C++11官方到N3690的当前措辞如下:
条件表达式e是核心常量表达式,除非e的求值将计算以下表达式之一:
除非使用常量expression初始化的整数或枚举类型的非易失性GL值引用具有先前初始化的非易失性常量对象,否则
以下是全局范围内的声明:
const int x2 = {42,43};
定义一个包含2个常量int对象的数组,使用{42, 43}
进行列表初始化
在8.5.1 dcl.init.aggr/2中:
当集合由初始化器列表初始化时,如8.5.4中所指定的,初始化器列表的元素以递增的下标或成员顺序作为集合成员的初始化器。
因此,第一个元素对象的初始化器是42
,第二个元素对象的初始化器是43
。
表达式*x
是一个左值和核心常量表达式。它需要数组到指针的转换和间接性--这两者都不会使表达式丧失作为核心常量表达式的资格。glvalue表达式引用x
的第一个element对象。*x
是整数类型(const int)的非易失性glvalue,它引用具有前面初始化的非易失性const对象,并使用常量表达式42
进行初始化。
因此,在常量表达式中允许对glvalue *x
应用左值到右值的转换,因此下面的表达式格式良好:
constexpr int y= *x;
无论是gcc还是clang目前都不接受这一常量表达,尽管根据标准它是很好的形式。
这是故意的吗?
完整的演示程序:
const int x2 = {42,43};const main int y= *x;int main() {}
同样,使用等效的左值x[0]
实现也会失败。
https://stackoverflow.com/questions/18903113
复制相似问题