专用模板类的静态成员初始化

时间:2010-02-26 15:11:13

标签: c++ static templates initialization specialization

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'

如果有可能,我宁愿保持初始化专用,因为数组包含一些特定于该类型的数据。

3 个答案:

答案 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;
}