Неопределенная ссылка на статический член шаблона класса, на который ссылается статический экземпляр

Пожалуйста, обратите внимание на следующее:

#include <string>
#include <unordered_map>

template <int N> class Object;
template <int N> class Thing;

template <int N>
class Factory {
private:
using FuncPtr = Object<N>*(*)(Thing<N>*);
static std::unordered_map<std::string, FuncPtr> map;
public:
static void insertInMap (const std::string& tag, FuncPtr funcPtr) {
map.emplace (tag, funcPtr);
}
};
template <int N>
std::unordered_map<std::string, typename Factory<N>::FuncPtr> Factory<N>::map;

// won't compile on GCC 4.8.1:
//template <> std::unordered_map<std::string, typename Factory<0>::FuncPtr> Factory<0>::map;

template <int N> struct Object {};

struct Blob : Object<0> {
static Blob prototype;
Blob() {Factory<0>::insertInMap ("Blob", Blob::create);}
Blob (Thing<0>*) {/* */}
static Object<0>* create (Thing<0>* x) {return new Blob(x);}
};
Blob Blob::prototype;  // Calls up Factory<0>::insertInMap during compile time, but crashes when run.

int main()
{
}

Итак, похоже, что Blob Blob::prototype; падает, потому что Factory<0>::map еще не был создан, поэтому я пытаюсь создать его с помощью строки:

template <> std::unordered_map<std::string, typename Factory<0>::FuncPtr> Factory<0>::map;

но он не скомпилируется (с GCC 4.8.1):

C:\Users\Andy\AppData\Local\Temp\ccsGlFeV.o:Practice.cpp:(.text$_ZN7FactoryILi0E
E11insertInMapERKSsPFP6ObjectILi0EEP5ThingILi0EEE[__ZN7FactoryILi0EE11insertInMa
pERKSsPFP6ObjectILi0EEP5ThingILi0EEE]+0x14): undefined reference to `Factory<0>:
:map'
collect2.exe: error: ld returned 1 exit status

1

Решение

Вместо специализация Factory<N>::map за <0>просто явно иллюстрировать примерами весь класс:

template class Factory<0>;

на месте //template <> ...

DEMO


ОБНОВИТЬ

Для Visual Studio, которая, похоже, все еще не может инициализировать статическое поле, даже если шаблон явно создан перед первым использованием, вы можете альтернативно специализировать весь класс:

template <>
class Factory<0> {
private:
typedef Object<0>*(*FuncPtr)(Thing<0>*);
static std::unordered_map<std::string, FuncPtr> map;
public:
static void insertInMap (const std::string& tag, FuncPtr funcPtr) {
map.emplace (tag, funcPtr);
}
};
std::unordered_map<std::string, Factory<0>::FuncPtr> Factory<0>::map;

или определите поле для Factory<0> (хотя я не знаю, почему VS принимает это и не вызывает ошибку, поскольку синтаксис недействителен):

std::unordered_map<std::string, Factory<0>::FuncPtr> Factory<0>::map;

ДЕМО 2

2

Другие решения


По вопросам рекламы [email protected]