Как обойти проблемы с шаблонами внутри Dll на С++?

Фон:

В настоящее время у меня есть проект игрового движка, структурированный в визуальной студии, так что мой «движок» скомпилирован в dll для использования другим проектом «Игра». Идея в том, что я могу поменять местами разные игровые проекты и по-прежнему использовать один и тот же код DLL движка. В своем коде движка я создаю свою собственную структуру, для которой будет использоваться весь остальной код движка. Это поможет отделить мою реализацию от остального кода и упростить модификацию, если это необходимо.

Поскольку весь мой код фреймворка будет использоваться внутри самой dll, а не в «Игре», я подумал, что смогу реализовать шаблоны. Тем не менее, я по-прежнему получаю сообщение об ошибке «неопределенный символ» каждый раз, когда пытаюсь внедрить шаблоны с помощью платформы Engine.

Проблема:

Есть ли способ обойти ошибки «неопределенный символ» для шаблонов из компоновщика в моей dll без необходимости явно определить каждый тип, который будет использовать мой шаблон (например, class template MyClass<int>, class template MyClass<float> и т. д.)? Если нет, есть ли какие-либо предложения о том, как я мог бы реализовать свой движок и различные игровые проекты, чтобы все еще оставалось гибким? Спасибо за любой вклад.

P.S. Я не хочу явно определять все типы, которые может использовать шаблонный класс, поскольку он стал бы довольно большим, если бы я захотел создать, скажем, свой собственный класс векторного шаблона (поскольку мне пришлось бы определять МНОГО разных классов).


person Jason    schedule 25.11.2016    source источник
comment
Я считаю, что явный экспорт экземпляров шаблонов — это обходной путь, если весь код находится в заголовочном файле. Более чистый способ (используемый, например, SFML) состоит в том, чтобы иметь заголовок шаблона только с объявлением, а затем внизу #include что-то вроде файла .inl, который определяет реализацию. Тогда это все во включаемых файлах, но сам заголовок чист для пользователя.   -  person mock_blatt    schedule 25.11.2016


Ответы (3)


Экземпляры шаблона генерируются во время компиляции, поэтому, если вы не хотите объявлять все возможные экземпляры по отдельности, вы должны переместить все определения шаблонов, чтобы включить их в заголовочный файл.

Один из распространенных способов сделать это для каждого класса — иметь все определения шаблонов во встроенном файле, например, в файле .inl или .cxx, а затем включить этот встроенный файл в конец соответствующего файла заголовка.

Например, для класса Foo с одной шаблонной функцией:

Содержание Foo.hpp:

class Foo
{
    template <typename T>
    void bar();
};

#include "Foo.inl" // Include template definitions

Содержание Foo.inl:

template <typename T>
void Foo::bar()
{
    // body
}

Таким образом, всякий раз, когда Foo::bar<T> используется с новым T, будет создан новый экземпляр шаблона.

person Adam Yaxley    schedule 25.11.2016

Шаблоны должны быть встроенным кодом. Их код создается на этапе генерации кода, когда компилятор сталкивается с использованием шаблона, с кодом для этого варианта использования. В общем, попытка заставить компилятор создать класс на основе шаблона является ошибкой, проблемой производительности и неудобством, которое противоречит цели наличия шаблонов.

В общем случае вам нужно объявить объект (переменную) специализированного шаблона, чтобы заставить компилятор сгенерировать его, если у вас ограниченное количество специализированных вариантов‹, вам нужно объявить их все. Даже в этом случае компиляторы стараются избегать создания новых функций, если они не виртуальные.

Большинство библиотек шаблонов полностью объявляют код методов в заголовках и могут вообще не иметь бинарных объектных файлов. Просто сделайте, как mock_blatt сказал в комментарии, сделайте объявления шаблонов в заголовке и реализации методов и друзей во включаемом файле, используемом из заголовка.

person Swift - Friday Pie    schedule 25.11.2016

«Я не хочу явно определять все типы, которые может использовать шаблонный класс, так как это станет довольно большим»

Что именно делает, по вашему мнению, должна содержаться библиотека DLL? Либо он содержит MyClass<float>, либо нет. И компилятор будет создавать экземпляры MyClass<T> для каждого известного ему типа, ваша DLL будет огромной.

person MSalters    schedule 25.11.2016