对于静态成员特化,如果不初始化成员,则将其视为特化宣言,这只是说“哦,不要从主模板实例化成员,因为其他地方有专门的定义”。应该提到的是,定义应该出现在 .cpp 文件中(否则,您将获得相反的效果:多个定义),并且不带初始化程序的声明仍应放置在头文件中。
现在正确的语法确实如下,并且应该not出现在头文件中,但是在.cpp
file
template<> int B<A, 1>::a[1] = { };
以下内容仍应出现在头文件中:
template<> int B<A, 1>::a[1];
这将作为专业宣言.
由此可见,您不能专门化仅具有默认构造函数且不可复制的成员,因为您需要以下语法:
// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();
C++0x 修复了这个问题:
// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};
对于我们当中的标准人来说,以下是引述:
14.7.3/6
:
如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在发生这种使用的每个翻译单元中;无需诊断。
14.7.3/15
:
如果声明包含初始值设定项,则模板的静态数据成员的显式特化是定义;否则,它是一个声明。 [注意:没有用于定义需要默认初始化的模板静态数据成员的语法。
template<> X Q<int>::x;
无论 X 是否可以默认初始化(8.5),这都是一个声明。 ]
3.2/3
:
每个程序都应包含该程序中使用的每个非内联函数或对象的确切定义;无需诊断。
3.2/5
:
类类型(第 9 条)、枚举类型(7.2)、具有外部链接的内联函数(7.1.2)、类模板(第 14 条)、非静态函数模板(14.5.5)可以有多个定义、类模板的静态数据成员 (14.5.1.3)、类模板的成员函数 (14.5.1.1) 或程序中未指定某些模板参数的模板特化 (14.7、14.5.4) [.. .]
对此的限制是“未指定某些模板参数”意味着我们are允许执行以下操作,将其放入标头中(因此可能具有此专业化的多个定义):
template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;
在您的情况下,您指定了所有参数,使其不被允许多个定义的一个定义规则所覆盖。