1

Пожалуйста, обратите внимание на следующее:Неопределенная ссылка на статический член шаблона класса ссылочного от статического экземпляра

#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

Компилятор * сбой * ??? Или вы просто получаете кучу сообщений об ошибках компилятора? –

+0

[Компилирует также здесь] (http://coliru.stacked-crooked.com/a/d9bc1a436fa0cd4c). Однако исполняемый файл падает, возможно, это значит, что означает OP. –

+0

Когда вы прокомментируете в раскоментированной строке, вы получите одно сообщение * ссылка *: http://coliru.stacked-crooked.com/a/25824e6fba8f074d –

ответ

2

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

template class Factory<0>; 

вместо //template <> ...

DEMO


UPDATE

Для 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; 

DEMO 2

+0

Да, это решение работает с GCC. Но когда я запускаю его на Visual Studio 2013, он по-прежнему падает из-за чтения nullptr. Какой компилятор прослушивается здесь? Есть ли решение, которое работает на обоих? Потому что я проверяю свою компиляцию с обоими компиляторами. – prestokeys

+0

@prestokeys: см. Обновление –

+0

Фиаско инициализации статического ордера происходит только при статических переменных в разных единицах компиляции –

Смежные вопросы