在C++11之前,我们只能对整型或枚举类型的静态常量成员执行类内初始化。 Stroustrup discusses this in his C++ FAQ ,给出了以下示例:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
};
以及下面的推理:
那么为什么会存在这些不方便的限制呢?类通常在头文件中声明,并且头文件通常包括在许多翻译单元中。但是,为了避免复杂的链接器规则,C++要求每个对象都有一个唯一的定义。如果C++允许在类中定义需要作为对象存储在内存中的实体,那么该规则将被打破。
然而,C++11放宽了这些限制,允许非静态成员的类内初始化(§12.6.2/8):
在非委托构造函数中,如果给定的非静态数据成员或基类未由mem-initializer-id指定(包括由于构造函数没有ctor-initializer而没有mem-initializer-list的情况),并且实体不是抽象类(10.4)的虚拟基类,则
第9.4.2节还允许在类内初始化非常数静态成员(如果它们用
constexpr
说明符标记)。
那么,我们在C++03中受到限制的原因是什么呢?我们只是简单地接受“复杂的链接器规则”,还是做了一些其他的改变,使之更容易实现?
简而言之,他们让链接器保持不变,但代价是使编译器比以前更加复杂。
也就是说,它仍然只产生一个定义,编译器必须对其进行排序,而不是导致链接器要排序的多个定义。
这也给程序员带来了一些更复杂的规则,但大部分都很简单,没什么大不了的。当您为单个成员指定了两个不同的初始值设定项时,就会出现额外的规则:
class X {
int a = 1234;
public:
X() = default;
X(int z) : a(z) {}
};
现在,这里的额外规则处理在使用非默认构造函数时用来初始化
a
的值。这个问题的答案相当简单:如果您使用的构造函数没有指定任何其他值,那么
1234
将用于初始化
a
--但是如果您使用的构造函数指定了其他值,那么
1234
基本上会被忽略。
例如:
#include <iostream>
class X {
int a = 1234;
public:
X() = default;
X(int z) : a(z) {}
friend std::ostream &operator<<(std::ostream &os, X const &x) {
return os << x.a;
int main() {
X y{5678};
std::cout << x << "\n" << y;
return 0;
}
结果:
1234
5678
我猜这个推理可能在模板最终定稿之前就已经写好了。毕竟,静态成员的类内初始化器所必需的“复杂链接器规则”对于C++11支持模板的静态成员已经是必要的了。
考虑一下
struct A { static int s = ::ComputeSomething(); }; // NOTE: This isn't even allowed,
// thanks @Kapil for pointing that out
// vs.
template <class T>
struct B { static int s; }
template <class T>
int B<T>::s = ::ComputeSomething();
// or
template <class T>