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

时间:2013-09-19 19:18:31

标签: c++ c++11 const constexpr

以下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 [0]是glvalue和非易失性)的整数(是的,它有类型const int)或枚举类型引用一个非易失性的const对象(是的它有类型const int)带有前面的初始化(yes用1初始化),用常量表达式初始化(​​yes 1是常量表达式)

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

1 == 1

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

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

2 个答案:

答案 0 :(得分: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() {}

然后一切都很好。

答案 1 :(得分:4)

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

有关详细说明,请参阅:

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

以下复制的报告:

  

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

     
    

条件表达式e是核心常量表达式,除非e的求值将评估以下表达式之一:

         
        
  • 左值 - 右值转换(4.1),除非它适用于
  •     
    •     
    • 一个非整数或枚举类型的非易失性glvalue,它引用具有前面初始化的非易失性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是一个   引用a的整数类型(const int)的非易失性glvalue   具有先前初始化的非易失性const对象,和   使用常量表达式42初始化。

     

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

constexpr int y = *x;
     

gcc或clang trunk目前都不接受此作为常量   表达,尽管它根据标准形成良好。

     

这是打算吗?

     

完整的演示程序:

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

实现同样失败,使用等效的左值x[0]   好。