单独的类模板声明和专门化

时间:2019-07-11 14:04:13

标签: c++ templates linker dllexport

我有一个类模板的声明。假设此模板的特殊化功能从数据库中保存并加载具有特定字符串ID的对象。我只需要对特定类型使用此模板,并将这些专业化知识放入不同的cpp文件中。

// TemplateInterface.h
template <typename T>
struct Foo
{
    static void save(T const& v);
    static T load();
};

假设我们使用此代码保存std :: tuple的值。

// TemplateInterface.cpp
template <>
struct __declspec(dllexport) Foo<Class1>
{
    static void save(Class1 const& v)
    {
        MyDatabase::save("class1-id", v);
    }
    static Class1 load()
    {
        return MyDatabase::load("class1-id");
    }
};

template <>
struct __declspec(dllexport) Foo<Class2>
{
    static void save(Class2 const& v)
    {
        MyDatabase::save("class2-id", v);
    }
    static Class2 load()
    {
        return MyDatabase::load("class2-id");
    }
};

如您所见,唯一的区别是字符串ID。 (没有__declspec(dllexport),此代码将不起作用。) 我发现,可以在单个文件中这样做:

// Source.cpp
template <typename T, typename Traits>
struct Helper
{
    static void save(T const& v)
    {
        MyDatabase::save(Traits::getID(), v);
    }
    static T load()
    {
        return MyDatabase::load(Traits::getID());
    }
};


template <typename T>
struct Foo
{
    static void save(T const& v);
    static T load();
};

struct Class1Traits 
{
    static std::string getID() { return "class1-id"; }
};

struct Class2Traits
{
    static std::string getID() { return "class2-id"; }
};

template<>
struct Foo<Class1> : Helper<Class1, Class1Traits> {};

template<>
struct Foo<Class2> : Helper<Class2, Class2Traits> {};

但是当我在其他文件中执行此操作时(TemplateInterface.h中的声明和TemplateInterface.cpp中的特殊化),我得到链接器错误:

error LNK2019: unresolved external symbol "public: static Class1__cdecl Foo<Class1>::load()" referenced in function _main

其他方法有相同的错误。 添加dllexport和使用无济于事。 你能帮我吗?

我知道的唯一解决方案是从模板规范中显式调用基类方法。但这是一个奇怪的解决方案。

1 个答案:

答案 0 :(得分:0)

模板实例化与模板专业化不同。

例如,获取以下代码,然后告诉我会发生什么:

// TemplateInterface.h
template <typename T>
struct Foo
{
    static T load();
};

int main() {
    int foo = Foo<int>::load();
}

然后,将其添加到单独的已编译cpp中:

template <>
struct Foo<int>
{
    static int load_special()
    {
        return 0;
    }
};

如您所见,根据专业化,没有Foo<int>::load(),只有Foo<int>::load_special()

您的代码实际上违反了ODR。

如果您希望对模板进行专业化处理,并且希望将其隐藏在自己的cpp文件中,则必须告诉编译器您的类型具有某些专业化处理,以防止其实例化主模板。

这是通过预先声明您的专业来完成的:

template<>
struct Foo<int>; // specialization elsewhere!