class 嵌套静态常量成员变量初始化 Clang vs GCC 哪个编译器是对的?
In class nested static const member variable initialization Clang vs GCC which compiler is right?
考虑以下代码:
#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 发出错误时:
error: 'i' was not declared in this scope
问:
两种编译器中哪一种符合C++标准?
在-class中初始化的静态常量成员必须由常量表达式初始化。在 i
的初始化器中,i
没有被常量表达式初始化(还),因此它本身也不是常量表达式。在我看来,两个编译器都是有罪的。
- clang,接受程序
- gcc,给出误导性的错误信息
GCC 抱怨名称未声明当然是错误的,因为 i
的声明点是 immediately after its declarator。
但是,可以说 GCC 拒绝整个片段是正确的。 [class.static.data]/3:
If a non-volatile const
static data member is of integral or
enumeration type, its declaration in the class definition can specify
a brace-or-equal-initializer in which every initializer-clause
that is an assignment- expression is a constant expression (5.20).
为了 [expr.const]/(2.7) 不失败,必须应用其四个子项目符号之一:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile
const
object with a preceding
initialization, initialized with a constant expression, or
- a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
- a non-volatile glvalue that refers to a non-volatile object defined with
constexpr
, or that refers to a non-mutable sub-object of such an
object, or
- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
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
视为 "properly" 在其初始化程序中初始化。我提交了错误 #26858.
考虑以下代码:
#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 发出错误时:
error: 'i' was not declared in this scope
问:
两种编译器中哪一种符合C++标准?
在-class中初始化的静态常量成员必须由常量表达式初始化。在 i
的初始化器中,i
没有被常量表达式初始化(还),因此它本身也不是常量表达式。在我看来,两个编译器都是有罪的。
- clang,接受程序
- gcc,给出误导性的错误信息
GCC 抱怨名称未声明当然是错误的,因为 i
的声明点是 immediately after its declarator。
但是,可以说 GCC 拒绝整个片段是正确的。 [class.static.data]/3:
If a non-volatile
const
static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment- expression is a constant expression (5.20).
为了 [expr.const]/(2.7) 不失败,必须应用其四个子项目符号之一:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile
const
object with a preceding initialization, initialized with a constant expression, or- a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
- a non-volatile glvalue that refers to a non-volatile object defined with
constexpr
, or that refers to a non-mutable sub-object of such an object, or- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
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
视为 "properly" 在其初始化程序中初始化。我提交了错误 #26858.