首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >当x为常量时,C++11中的x[0] == 1常量表达式?

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

Stack Overflow用户
提问于 2013-09-20 03:18:31
回答 2查看 671关注 0票数 19

下面的C++11程序是不是格式错误?

代码语言:javascript
复制
const int x[] = {1,2,3};

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

int main() {}

gcc和clang似乎是这么认为的,但是为什么x[0] == 1不是一个恒定的表达呢?

代码语言:javascript
复制
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数组的第一个元素满足这些条件。

代码语言:javascript
复制
1 == 1

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

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

EN

回答 2

Stack Overflow用户

发布于 2013-09-20 03:53:27

在5.19中:

...expression是一个常量表达式,除非它包含以下内容之一...:

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

代码语言:javascript
复制
- 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;.

  • a声明的constant:constexpr int x[] = {1,2,3};.

  • a临时对象初始化的常量整数(或枚举)声明constexpr

您的示例确实包含了左值到右值的转换,但没有任何例外,因此x不是常量表达式。但是,如果您将其更改为:

代码语言:javascript
复制
constexpr int x[] = {1,2,3};

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

int main() {}

那么一切都很好。

票数 11
EN

Stack Overflow用户

发布于 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值引用具有先前初始化的非易失性常量对象,否则

  • 左值到右值转换(4.1)

以下是全局范围内的声明:

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]实现也会失败。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18903113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档