当x是const int []时,x [0] == 1 C++ 11中的常量表达式?

And*_*zos 20 c++ const constexpr c++11

以下C++ 11程序是否格式错误?

const int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}
Run Code Online (Sandbox Code Playgroud)

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:
Run Code Online (Sandbox Code Playgroud)

一个非易失性glvalue(是的,x [0]是glvalue和非易失性)的整数(是的,它有类型const int)或枚举类型引用一个非易失性的const对象(是的它有类型const int)使用前面的初始化(是初始化为1),使用常量表达式初始化(​​是1是常量表达式)

似乎是真的,x数组的第一个元素满足这些条件.

1 == 1
Run Code Online (Sandbox Code Playgroud)

这是编译器错误,标准缺陷,还是我错过了什么?

5.19 [expr.const]的哪一部分说这不是一个常量表达式?

rod*_*igo 11

在5.19:

[...]表达式是一个常量表达式,除非它涉及以下之一[...]:

  • 除非适用,否则左值到右值的转换(4.1)

    • 一个整数或枚举类型的glvalue,它引用一个带有前面初始化的非易失性const对象,用一个常量表达式初始化,或者
    • 一个文字类型的glvalue,它指的是用constexpr定义的非易失性对象,或者指的是这样一个对象的子对象,或者
    • 一个文字类型的glvalue,它引用一个用常量表达式初始化的非易失性临时对象

说白了,左值到右值的转换只能在常量表达式中完成,如果:

  • 用常量初始化的常量整数(或枚举)声明:const int x = 3;.
  • 声明constexpr:constexpr int x[] = {1,2,3};.
  • 用常量表达式初始化的临时对象......

您的示例包括左值到右值的转换,但没有这些异常,因此x不是常量表达式.但是,如果您将其更改为:

constexpr int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}
Run Code Online (Sandbox Code Playgroud)

一切都很好.

  • @ user1131467:不,`x [0]`没有初始化为任何东西.```被初始化为`{1,2,3}`,因此`x [0]`的值最终为'1`. (6认同)
  • 8.5.1p2"当一个[array]由初始化列表初始化时,初始化列表的元素被作为[array]成员的初始化者,增加下标或成员顺序." 所以在`const int x [] = {1,2,3}`中,`1`是对象`x [0]`的初始值 - 抱歉,但是`x [0]`显然是初始化的. (3认同)
  • @ user1131467:仔细检查第二个子弹显示为什么第一个不适用...`x [0]`显然是一个*子对象*,而不是一个完整的对象,并且子弹被允许在子弹#2中而不是子弹# 1. (3认同)