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

101*_*010 9 c++ gcc clang static-members language-lawyer

考虑以下代码:

#include <iostream>

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

int main() {
  std::cout << Foo::i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Clang 3.7版汇编了这个和输出1.

现场演示

虽然GCC版本5.3发出错误:

错误:'i'未在此范围内声明

现场演示

问:

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

Col*_*mbo 4

GCC 抱怨名称未声明当然是错误的,因为声明点i紧接在其声明符之后

然而,GCC 总体上拒绝该片段可以说是正确的。[类.静态.数据]/3 :

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

为了使[expr.const]/(2.7)不失败,必须应用其四个子项目之一:

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

  • 整型或枚举类型的非易失性泛左值,引用具有前面初始化的完整非易失性const对象,并使用常量表达式进行初始化,或者
  • 引用字符串文字 (2.13.5) 的子对象的非易失性泛左值,或者
  • 一个非易失性泛左值,它引用用 定义的非易失性对象constexpr,或者引用此类对象的非可变子对象,或者
  • 文字类型的非易失性泛左值,引用其生命周期开始于 的求值内的非易失性对象e

(2.7.1) 是唯一合理的候选者,但由于i之前没有使用初始化器进行初始化,所以它不适用。

请注意,Clang 是完全一致的

constexpr int i = i;
void f() {
    // constexpr int j = j; // error
    static constexpr int h = h;
}
Run Code Online (Sandbox Code Playgroud)

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