对从静态实例引用的类模板的静态成员的未定义引用

Undefined reference to static member of class template referenced from static instance

本文关键字:引用 静态成员 未定义 静态 实例      更新时间:2023-10-16

请查看以下内容:

#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:UsersAndyAppDataLocalTempccsGlFeV.o:Practice.cpp:(.text$_ZN7FactoryILi0E
E11insertInMapERKSsPFP6ObjectILi0EEP5ThingILi0EEE[__ZN7FactoryILi0EE11insertInMa
pERKSsPFP6ObjectILi0EEP5ThingILi0EEE]+0x14): undefined reference to `Factory<0>:
:map'
collect2.exe: error: ld returned 1 exit status

与其将Factory<N>::map专门化为<0>,不如显式地实例化整个类:

template class Factory<0>;

代替//template <> ...

演示


更新

对于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