除非明确专门化,否则模板类的静态成员不会被实例化?

时间:2013-10-13 16:47:08

标签: c++ templates singleton linker-errors static-members

我有一个模板单例类,带有静态实例和静态getInstance()方法。但是,我在g ++(MinGW)的实例上得到一个未定义的引用错误;起初,我认为这是链接顺序错误,但无论我把它们放在哪个顺序,我都会得到同样的东西。

但是,我发现如果我明确地专门化了实例,它就会编译(这不是一个可接受的解决方案)。所以,这是代码:

Singleton.hpp:

#ifndef SINGLETON_HPP
#define SINGLETON_HPP

#include <iostream>

template<int X=100>
class Singleton {
protected:
    static Singleton<X> *instance;
public:

    static Singleton<X>& getInstance() {
        if(!Singleton<X>::instance) {
            Singleton<X>::instance = new Singleton<X>();
        }
        return *Singleton<X>::instance;
    }

    void foo() {
        std::cout << "Test<" << X << ")::foo()" << std::endl;
    }
};

#endif

Singleton.cpp:

#include "Singleton.hpp"

template<int X>
Singleton<X>* Singleton<X>::instance = NULL;

#ifdef SPECIALIZE
template<>
Singleton<100>* Singleton<100>::instance = NULL;
#endif

Main.cpp的:

#include "Singleton.hpp"

int main(int ac, char *av[]) {
    Singleton<100> &sing = Singleton<100>::getInstance();
    sing.foo();
}

然后是三种不同的编译方式和输出:

没有专业化,SingletonMain.o首先链接:

C:\Test>g++ -c Singleton.cpp

C:\Test>g++ -c SingletonMain.cpp

C:\Test>g++ -o Singleton.exe SingletonMain.o Singleton.o
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x7): undefined reference to `Singleton<100>::instance'
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x1c): undefined reference to `Singleton<100>::instance'
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x21): undefined reference to `Singleton<100>::instance'
collect2: ld returned 1 exit status

没有专业化,Singleton.o首先链接:

C:\Test>g++ -c Singleton.cpp

C:\Test>g++ -c SingletonMain.cpp

C:\Test>g++ -o Singleton.exe Singleton.o SingletonMain.o
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x7): undefined reference to `Singleton<100>::instance'
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x1c): undefined reference to `Singleton<100>::instance'
SingletonMain.o:SingletonMain.cpp:(.text$_ZN9SingletonILi100EE11getInstanceEv[Singleton<100>::getInstance()]+0x21): undefined reference to `Singleton<100>::instance'
collect2: ld returned 1 exit status

专业化:

C:\Test>g++ -DSPECIALIZE -c Singleton.cpp

C:\Test>g++ -DSPECIALIZE -c SingletonMain.cpp

C:\Test>g++ -DSPECIALIZE -o Singleton.exe Singleton.o SingletonMain.o

现在,似乎有人在这里遇到类似问题 - C++ template static member instantiation - 但“解决方案”是针对您可能使用的每种类型进行明确的专业化......这似乎完全失败了模板的目的......所以必须有更好的方法,对吗?

1 个答案:

答案 0 :(得分:1)

您必须将静态成员定义移动到标题。就像模仿其他所有内容一样,类模板的静态成员的定义必须存在于使用它的每个翻译单元中。这基本上意味着它属于标题。

引用C ++ 11,[temp]§6

  

函数模板,类模板的成员函数或类模板的静态数据成员应在每个隐式实例化的翻译单元中定义(14.7.1),除非相应的在某些翻译单元中明确地实例化了专业化(14.7.2);无需诊断。

(强调我的)