class A
{
};
template <typename A, int S>
class B
{
public:
static int a[S];
B()
{
a[0] = 0;
}
};
template<> int B<A, 1>::a[1];
int main()
{
B<A, 1> t;
t;
}
它在GCC 4.1下编译,但没有链接:
static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'
如果有可能,我宁愿保持初始化专用,因为数组包含一些特定于该类型的数据。
答案 0 :(得分:34)
对于静态成员特化,如果不初始化成员,则将其视为专门化声明,它只是说“哦,不要从主模板中实例化成员,因为在其他地方有一个专门的定义“。应该提到的是,定义应该出现在.cpp文件中(否则,您将获得相反的结果:多个定义),并且没有初始化程序的声明仍应放在头文件中。
现在正确的语法确实如下,它应该不出现在头文件中,而是出现在.cpp
文件中
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{};
对于我们中间的Standardese人,这里有引号:
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) [...]
将此限制为“未指定某些模板参数”意味着我们 允许执行以下操作,将其放入标题中(因此可能具有此专业化的多个定义) :
template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;
在您的情况下,您指定了所有参数,使得它不被允许多个定义的一个定义规则所覆盖。
答案 1 :(得分:1)
您需要实际为其分配值。
template<> int B<A, 1>::a[1] = {0};
答案 2 :(得分:0)
它没有链接,因为您没有为静态成员定义值。
template<> int B<A, 1>::a[] = { 0 };
编辑:
顺便说一句:我总是喜欢使用boost :: array而不是本机C类型:
class A { };
template <typename A, std::size_t S>
class B
{
public:
static boost::array<int, S> a;
B() { a[0] = 0; }
};
template<> boost::array<int, 1> B<A, 1>::a = { };
int main()
{
B<A, 1> t;
cout << t.a[0] << endl;
}