问题
I have a template singleton class, with a static instance, and a static getInstance() method. However, I'm getting an undefined reference error on the instance from g++ (MinGW); at first, I thought it was linker-order error, but I get the same thing no matter which order I put them in.
However, I found that if I explicitly specialize the instance, it does compile (which isn't an acceptable solution). So, here's the code:
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();
}
Then here's the three different ways of compiling, and the output:
No specialization, SingletonMain.o linked first:
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
No specialization, Singleton.o linked first:
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
With specialization:
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
Now, there does seem to be someone having a similar problem here -- C++ template static member instantiation -- but the "solution" was to have an explicit specialization for each type you might use...which seems to totally defeat the purpose of templates...so there has to be a better way, right?
回答1:
You must move the static member definition to the header. Just like with everything else templated, a definition of a static member of a class template must be present in every translation unit where it's used. This basically means it belongs into the header.
Quoting C++11, [temp]§6
:
A function template, member function of a class template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.
(Emphasis mine)
来源:https://stackoverflow.com/questions/19347671/static-member-of-template-class-not-instantiated-unless-explicitly-specialized