Явная идиома для создания экземпляра шаблонного кода — без включения его источника

Очень распространенный шаблон кодирования в C и C ++ для функций, ADT и классов должен иметь:

  • Файл заголовка .h с объявлением (функции класса).
  • Файл реализации .cpp с актуальным кодом.

Они скомпилированы в отдельный объект (общий или нет). Другой код, использующий объявленную сущность (назовем ее ‘foo’), включает файл foo.h, компилируется отдельно и затем ссылается на foo.o.

Однако с шаблонным foo это невозможно: без указания того, для какого типа требуется создание экземпляра, foo.o бесполезен. Кажется, что все делают, включая код реализации (который обычно был бы foo.cpp) в том же модуле перевода, что и пользовательский код.

Я хотел бы быть в состоянии избежать этого, используя некоторый механизм, который не требует включения foo.cpp. В идеале это должно работать:

main.cpp:

#include "foo.h"int main() {
foo<int>();
}

foo.h:

template<typename T> void foo();

foo.cpp:

template<typename T> void foo() {
// implementation here
}

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

template foo<int>();

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

Замечания: Конечно, весь смысл в том, что код для модуля foo (foo.h, foo.cpp) не «знает», какие экземпляры нужны, например, не знает, main() буду использовать foo<int>() или же foo<unsigned char>(),

2

Решение

Это явное воплощение.

template foo<int>();

Это говорит компилятору сделать foo реализовано для int, Как будто вы пишете реализацию для int в вашем .cpp файл. Это полезно, если вы знаете, какие типы будут использоваться в будущем. Это может сократить общее время компиляции в вашем проекте, если вы используете foo<int> во многих переводческих подразделениях. Например:

файл FooBar.h:

template <typename T>
class Bar
{
public:
T data;
void func();
};

template<typename T> void foo();

файл FooBar.cpp:

template <typename T>
void Bar<T>::func()
{
}

template <typename T>
void foo() {
}

// explicit instantiation

template class Bar<int>;
template class Bar<std::string>;
template foo<int>();
template foo<float>();

Основная проблема в том, что ваш foo а также Bar как шаблонные вещи должны использоваться только с экземплярами. Например, foo ограничено int а также float, а также Bar ограничено int а также std::string,

2

Другие решения

На самом деле, только для примера, нам даже не нужно дублировать подпись:

template decltype(foo<int>) foo;

это не имеет большого значения в этом примере, но имеет значение, если ваша подпись длинная и утомительная.

0

По вопросам рекламы [email protected]