19

以下 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:

整数(是的,它具有 const int 类型)或引用非易失性 const 对象的枚举类型(是的,它具有 const int 类型)的非易失性左值(是的,x[0] 是左值且非易失性)带有前面的初始化(是的,用 1 初始化),用常量表达式初始化(​​是的,1 是常量表达式)

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

1 == 1

?

这是编译器错误、标准缺陷还是我遗漏了什么?

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

4

2 回答 2

11

在 5.19 中:

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

  • 左值到右值的转换(4.1),除非它应用于

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

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

  • 用常量初始化的常量整数(或枚举)声明: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() {}

那么一切都很好。

于 2013-09-19T19:53:27.457 回答
4

按照标准的当前措辞,这是一个编译器错误,并且程序格式正确。现在正在考虑它是否应该是一个标准缺陷,因为它很难实施。

详细解释见:

https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/Nv5_2dCHm6M

报告复制如下:

C++11 官方到 N3690 的当前措辞包括以下内容:

条件表达式 e 是一个核心常量表达式,除非 e 的计算将计算以下表达式之一:

  • 左值到右值的转换(4.1),除非它应用于
    • 整数或枚举类型的非易失性左值,它引用具有先前初始化的非易失性 const 对象,用常量表达式初始化

全局范围内的以下声明:

const int x[2] = {42, 43};

定义一个由 2 个 const int 对象组成的数组,列表初始化为{42, 43}

在 8.5.1 [dcl.init.aggr]/2 中:

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。

所以第一个元素对象42的初始值设定项是 ,第二个元素对象的初始值设定项是43

该表达式*x是一个左值和一个核心常量表达式。它需要一个数组到指针的转换和一个间接 - 这两者都不会取消表达式作为核心常量表达式的资格。glvalue 表达式引用 的第一个元素对象x*x是一个整数类型 (const int) 的非易失性左值,它引用一个具有先前初始化的非易失性 const 对象,并使用常量表达式初始化42

因此,在常量表达式中允许应用到左值的左值到右值转换*x ,因此以下是格式正确的:

constexpr int y = *x;

gcc 或 clang trunk 目前都不接受它作为一个常量表达式,尽管它根据标准是正确的。

这是故意的吗?

完整的演示程序:

const int x[2] = {42, 43};
constexpr int y = *x;
int main() {}

实现同样以等效的左值失败x[0]

于 2013-09-20T11:39:06.890 回答