在类嵌套的静态const成员变量初始化Clang vs GCC哪个编译器是对的?

时间:2016-03-04 09:55:12

标签: c++ gcc clang language-lawyer static-members

考虑以下代码:

#include <iostream>

struct Foo {
  static int const i = i + 1;
};

int main() {
  std::cout << Foo::i << std::endl;
}

Clang版本3.7编译并输出1

Live Demo

虽然GCC 5.3版本发出错误:

  

错误:&#39;我&#39;未在此范围内声明

Live Demo

问:

两个编译器中的哪一个符合C ++标准?

2 个答案:

答案 0 :(得分:4)

由于i的声明是immediately after its declarator,因此GCC当然不应该抱怨该名称未被宣布。

然而,海湾合作委员会可以说完全拒绝整个片段。 [class.static.data]/3

  

如果非易失性const静态数据成员是完整的或   枚举类型,它在类定义中的声明可以指定   一个大括号或等于初始化 ,其中每个初始化子句   这是一个赋值 - 表达式是一个常量表达式(5.20)。

并且[expr.const]/(2.7)不要失败,其四个子弹中的一个必须适用:

  

左值 - 右值转换(4.1),除非它适用于

     
      
  • 一个非整数或枚举类型的非易失性glvalue,它引用一个完整的非易失性const对象与前一个   初始化,使用常量表达式
  • 初始化   
  • 一个非易失性glvalue,它引用字符串文字的子对象(2.13.5)或
  •   
  • 一个非易失性glvalue,它引用一个用constexpr定义的非易失性对象,或者引用这种不可变的子对象。   对象,或
  •   
  • 文字类型的非易失性glvalue,引用一个非易失性对象,其生命周期始于e的评估;
  •   

(2.7.1)是唯一合理的候选者,但由于i之前未使用初始化程序初始化,因此不适用。

请注意,Clang是completely consistent

constexpr int i = i;
void f() {
    // constexpr int j = j; // error
    static constexpr int h = h;
}

它似乎将i视为&#34;正确&#34;如果它具有静态存储持续时间,则在其初始化程序中初始化我提交了错误#26858

答案 1 :(得分:2)

在类中初始化的静态const成员必须由常量表达式初始化。在i的初始值设定项中,i未通过常量表达式(尚未)初始化,因此本身不是常量表达式。在我看来,两个编译器都是有罪的。

  • clang,接受该计划
  • gcc,用于提供误导性错误消息