7.5 Где шаблон?
Шаблоны C++ — это первая языковая возможность, которая требует от среды большей интеллектуальности, чем обычно встречается в системах UNIX. Компилятору и компоновщику необходимо как-то убедиться, что каждая инстанция шаблона появляется ровно один раз в исполняемом файле, если она нужна, и совсем не появляется в противном случае. Существует два основных подхода к этой задаче, которые называются моделью Borland и моделью Cfront.
- Модель Borland
- Borland C++ решил проблему инстанциации шаблонов, добавив в компоновщик код, эквивалентный общим блокам; компилятор генерирует инстанции шаблонов в каждом файле трансляции, использующем их, а компоновщик объединяет их вместе. Преимущество этой модели заключается в том, что компоновщику нужно только рассматривать сами объектные файлы; нет внешней сложности, о которой нужно беспокоиться. Недостатком является то, что время компиляции увеличивается, поскольку код шаблона компилируется повторно. Код, написанный для этой модели, как правило, включает определения всех шаблонов в заголовочном файле, так как они должны быть видны для инстанциации.
- Модель Cfront
- Переводчик AT&T C++, Cfront, решил проблему инстанциации шаблонов, создав понятие хранилища шаблонов — автоматически поддерживаемого места, где хранятся инстанции шаблонов. Более современная версия хранилища работает следующим образом: при построении отдельных объектных файлов компилятор помещает любые определения и инстанциации шаблонов, встреченные им, в хранилище. На этапе компоновки обёртка компоновщика добавляет объекты из хранилища и компилирует любые необходимые инстанции, которые ранее не были сгенерированы. Преимуществами этой модели являются более высокая скорость компиляции и возможность использования системного компоновщика; для реализации модели Borland поставщик компилятора также должен заменить компоновщик. Недостатками являются значительно повышенная сложность и, следовательно, потенциальные ошибки; для некоторых кодов это может быть столь же прозрачно, но на практике может быть очень сложно собрать несколько программ в одной директории и одну программу в нескольких директориях. Код, написанный для этой модели, как правило, отделяет определения нелинейных шаблонов членов в отдельный файл, который должен компилироваться отдельно.
При использовании с GNU ld версии 2.8 или более поздней в системе ELF, такой как GNU/Linux или Solaris 2, или в Microsoft Windows, G++ поддерживает модель Borland. В других системах G++ не реализует ни одну из автоматических моделей.
У вас есть следующие варианты решения проблем с инстанциацией шаблонов:
- Компилируйте свой код, использующий шаблоны, с
-frepo. Компилятор генерирует файлы с расширением ‘.rpo’, перечисляющие все инстанции шаблонов, используемые в соответствующих объектных файлах, которые могли быть инстанцированы там; обёртка компоновщика, ‘collect2’, затем обновляет файлы ‘.rpo’, чтобы указать компилятору, где разместить эти инстанциации, и перекомпилировать любые затронутые объектные файлы. Накладные расходы на время компоновки незначительны после первого прохода, так как компилятор продолжает размещать инстанциации в тех же файлах.Это лучший вариант для прикладного кода, написанного для модели Borland, так как он просто работает. Код, написанный для модели Cfront, нужно изменить, чтобы определения шаблонов были доступны в одном или нескольких точках инстанциации; обычно это просто добавление
#include <tmethods.cc>в конец каждого заголовочного файла шаблонов.Для кода библиотек, если вы хотите, чтобы библиотека предоставляла все необходимые инстанциации шаблонов, просто попробуйте связать все её объектные файлы вместе; компоновка завершится неудачно, но это вызовет инстанциации в качестве побочного эффекта. Однако будьте осторожны, так как это может вызвать конфликты, если несколько библиотек пытаются предоставить одинаковые инстанциации. Для большего контроля используйте явную инстанциацию, как описано в следующем пункте.
- Компилируйте свой код с
-fno-implicit-templatesдля отключения неявной генерации инстанций шаблонов и явного создания всех используемых инстанций. Этот подход требует больше знаний о том, какие инстанции нужны, чем другие, но он менее загадочен и позволяет больше контроля. Вы можете разбросать явные инстанциации по всему вашему програмному коду, возможно, поместив их в файлы трансляции, где инстанции используются, или в файлы трансляции, которые определяют сами шаблоны; вы можете поместить все необходимые явные инстанциации в один большой файл; или вы можете создать небольшие файлы, как#include "Foo.h" #include "Foo.cc" template class Foo<int>; template ostream& operator << (ostream&, const Foo<int>&);для каждой из необходимых инстанций и создать библиотеку инстанциации шаблонов из них.
Если вы используете код модели Cfront, вы, вероятно, можете обойтись без
-fno-implicit-templatesпри компиляции файлов, которые не ‘#include’ определения шаблонов членов.Если вы используете один большой файл для инстанциации, вы можете скомпилировать его без
-fno-implicit-templates, чтобы получить все инстанции, необходимые вашим явным инстанциациям (но не другими файлами), без необходимости указывать их также.Стандарт ISO C++ 2011 позволяет делать предварительную декларацию явных инстанциаций (с
extern). G++ поддерживает декларации явных инстанциаций в режиме C++98 и расширил синтаксис инстанциации шаблонов для поддержки инстанциации данных поддержки компилятора для класса шаблона (т.е. vtable) без инстанциации каких-либо его членов (сinline), и инстанциацию только статических данных членов класса шаблона без данных поддержки или функций-членов (с (static):extern template int max (int, int); inline template class Foo<int>; static template class Foo<int>;
- Ничего не делайте. Представьте, что G++ реализует автоматическое управление инстанциацией. Код, написанный для модели Borland, работает нормально, но каждый файл трансляции содержит инстанции каждого используемого шаблона. В большой программе это может привести к неприемлемому количеству дублирования кода.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Template-Instantiation.html