在类嵌套静态常量成员变量初始化 Clang vs GCC 哪个编译器是正确的

In class nested static const member variable initialization Clang vs GCC which compiler is right?

本文关键字:GCC 编译器 vs Clang 静态 嵌套 常量 成员 初始化 变量      更新时间:2023-10-16

考虑以下代码段:

#include <iostream>
struct Foo {
  static int const i = i + 1;
};
int main() {
  std::cout << Foo::i << std::endl;
}

Clang 版本 3.7 对此进行了编译并输出1

现场演示

虽然 GCC 版本 5.3 会发出错误:

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

现场演示

问:

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

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

但是,GCC 总体上拒绝该代码段可以说是正确的。[class.static.data]/3:

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

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

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

  • 整数或枚举类型的非易失性 gl值,指的是具有前面的完整非易失性const对象 初始化,使用常量表达式初始化,
  • 引用字符串文本 (2.13.5) 的子对象的非易失性 gl值,或
  • 一个非易失性
  • gl值,它指的是用 constexpr 定义的非易失性对象,或者指的是这样一个 对象,或
  • 文字类型的非易失性 gl值,指的是其生命周期始于e评估的非易失性对象;

(2.7.1) 是唯一合理的候选者,但由于 i 以前没有使用初始值设定项进行初始化,因此它不适用。

请注意,Clang 是完全一致的:

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

如果i具有静态存储持续时间,则它似乎将视为在其初始值设定项中"正确"初始化。我提交了错误#26858。

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

  • 叮当当,用于接受程序
  • GCC,用于提供误导性错误消息