Отдельное объявление шаблона класса и специализация - PullRequest
1 голос
/ 11 июля 2019

У меня есть объявление шаблона класса.Предположим, что специализации этого шаблона сохраняют и загружают объект из базы данных с определенным идентификатором строки.Мне нужно использовать этот шаблон только для определенных типов, и я поместил эти специализации в разные 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");
    }
};

Как видите, единственная разница - идентификаторы строк.(Без __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 голосов
/ 11 июля 2019

Создание шаблона не совпадает со специализацией шаблона.

Например, возьмите этот код и скажите мне, что происходит:

// 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!
...