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, работает нормально, но каждый файл трансляции содержит экземпляции каждого используемого шаблона. В большой программе это может привести к неприемлемому количеству дублирования кода.
Далее: Связанные функции-члены, Предыдущее: Интерфейс C++, Вверх: Расширения C++ [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/Template-Instantiation.html