提问人:kaspy 提问时间:2/26/2010 更新时间:2/27/2010 访问量:18535
专用模板类的静态成员初始化
static member initialization for specialized template class
问:
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'
如果可能的话,我更愿意保持初始化的专用性,因为数组包含一些特定于该类型的数据。
答:
您需要实际为其分配一个值。
template<> int B<A, 1>::a[1] = {0};
评论
error: conflicting declaration ‘int B<A, 1>::a’
它不会链接,因为您没有为静态成员定义值。
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;
}
对于静态成员专用化,如果不初始化成员,则将其视为专用化声明,它只是说“哦,不要从主模板实例化成员,因为其他地方有专用定义”。应该提到的是,定义应该出现在 .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;
在本例中,您指定了所有参数,使其不被允许多个定义的一个定义规则所涵盖。
评论
typename A