Подтвердить что ты не робот

Шаблоны С++ объявляют в .h, определяют в .hpp

Я увидел некоторый код, в котором разработчик определил шаблон класса в файле .h и определил его методы в файле .hpp. Это застало меня врасплох.

Существуют ли особые соглашения в С++ при работе с шаблонами и в каких файлах они должны быть?

Например, у меня был шаблон класса Vector с методами для векторных операций (добавление, вычитание, точка и т.д.). Я также хотел бы специализировать определенные функции, если аргумент шаблона является float (операторы сравнения). Как бы вы отделили все это между файлами (укажите ли .h,.hpp,.cpp).

4b9b3361

Ответ 1

Обычно (по моему опыту, YMMV) файл hpp является #include -ed CPP файлом. Это делается для того, чтобы разбить код на два физических файла, основной и файл данных реализации, о которых не нужно знать пользователям вашей библиотеки. Это делается следующим образом:

super_lib.h(единственный файл, которому ваши клиенты должны #include)

template<...> class MyGizmo
{
public:
  void my_fancy_function();
};

#include "super_lib_implementation.hpp"

super_lib_implementation.hpp(ваши клиенты не напрямую #include)

template<...> void MyGizmo<...>::my_fancy_function()
{
 // magic happens
}

Ответ 2

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

С++ 0x вводит объявления extern шаблонов, которые позволяют вам определять явные специализации в другом исходном файле (единица перевода). Это уже существует как расширение в GCC и, возможно, других платформах.

Разделение на два файла может помочь "скрыть" реализацию немного, или, возможно, дать некоторую лень с помощью doxygen.

Ага! Это также возможно улучшить время компиляции с предварительно скомпилированными заголовками. Компилятор может кэшировать заголовки для каждого файла. Затем может быть изменен отдельный заголовок "реализация", не касаясь заголовка "interface". Но не наоборот, заголовок реализации по-прежнему будет занимать большую часть времени компиляции, а коэффициент усиления будет очень хрупким и зависит от платформы и конкретных изменений. В итоге PCH улучшает время над несколькими исходными файлами, а оптимизация зависимостей заголовков бессмысленна.

Ответ 3

Мне кажется, что это путаный способ разделения кода. .h обозначает заголовок и .hpp для заголовка С++. Помещение определений шаблонов в .hpp, в то время как другой код в .h, похоже, нарушает расширение файла.

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

Исключения - это когда вы используете явное создание экземпляра и точно знаете, какие экземпляры вам понадобятся. Представьте, что у вас есть шаблон и ровно два его экземпляра:

template<typename T>
struct SymbolTable {
  T *lookup();
  // ...
};

template struct SymbolTable<GlobalSym>;
template struct SymbolTable<LocalSym>;

Вам не нужно вставлять определение lookup и других в заголовок. Вы можете поместить их в файл .cpp вместе с двумя явными директивами создания экземпляров.

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

Ответ 4

Я никогда не слышал о объявлении классов в .h и определениях шаблонов в .hpp. Каждый проект, который я видел, использовал подход, который .h и .hpp означает одно и то же, и вы должны стандартизировать один (обычно .h).

Методы шаблонов можно поместить в конец файла .h, или их можно поместить в отдельные файлы -inl.h (как предложено Руководство по стилю Google С++, например).

Ответ 5

Я думаю, что один из аспектов разделения файла интерфейса (.h) и реализации (.hpp) заключается в том, что пользователю шаблона (то есть другому разработчику) нужно будет только посмотреть файл .h, чтобы понять, как использовать шаблон, не отвлекаясь на его фактическую реализацию.

Ответ 6

Если мы определяем шаблон класса в файле .h и определяем его методы в файле .hpp, мы должны #include.hpp файл в файле .h. Легче просто определить методы в конце файла .h(тогда не требуется файл .hpp).

Ответ 7

Библиотека Boost использует ".hpp" для заголовков, содержащих декларацию и реализацию. В таких случаях нет необходимости связываться с (предварительно скомпилированной) библиотекой.

В отношении идеи Boost такое расширение, как ".inl", может быть хорошей идеей описать исходный файл "реализации" заголовка объявления шаблона.