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

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

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

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

18
задан rhubarb 19 August 2010 в 21:14
поделиться

6 ответов

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

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
}
18
ответ дан 30 November 2019 в 08:37
поделиться

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

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

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

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

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

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

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

2
ответ дан 30 November 2019 в 08:37
поделиться

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

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

1
ответ дан 30 November 2019 в 08:37
поделиться

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

0
ответ дан 30 November 2019 в 08:37
поделиться

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

1
ответ дан 30 November 2019 в 08:37
поделиться

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

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

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

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

2
ответ дан 30 November 2019 в 08:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: