Spec-Zone.ru › GCC 14

7.5 Где шаблон?

Шаблоны C++ были первой языковой особенностью, которая потребовала от среды большей интеллектуальности, чем традиционно предоставлялось на системе UNIX. Компилятору и компоновщику каким-то образом нужно убедиться, что каждая экземпляризация шаблона присутствует ровно один раз в исполняемом файле, если она необходима, и вообще отсутствует в противном случае. Для решения этой проблемы существуют два основных подхода, которые называются моделью Borland и моделью Cfront.

Модель Borland

Borland C++ решил проблему экземпляризации шаблонов, добавив к своему компоновщику код, эквивалентный общим блокам; компилятор генерирует экземпляризации шаблонов в каждом файле трансляции, использующем их, а компоновщик сводит их вместе. Преимущество этой модели заключается в том, что компоновщику нужно рассматривать только сами объектные файлы; нет внешней сложности, о которой нужно беспокоиться. Недостатком является увеличение времени компиляции, поскольку код шаблона компилируется многократно. Код, написанный для этой модели, обычно включает определения всех шаблонов в файле заголовков, поскольку они должны быть видны для экземпляризации.

Модель Cfront

Переводчик C++ от AT&T, Cfront, решил проблему экземпляризации шаблонов, создав понятие хранилища шаблонов — автоматически поддерживаемого места, где хранятся экземпляризации шаблонов. Более современная версия хранилища работает следующим образом: по мере построения отдельных объектных файлов компилятор помещает в хранилище все обнаруженные определения и экземпляризации шаблонов. На этапе компоновки обёртка компоновщика добавляет объекты из хранилища и компилирует любые необходимые экземпляризации, которые ранее не были сгенерированы. Преимуществами этой модели являются более оптимальная скорость компиляции и возможность использования системного компоновщика; для реализации модели Borland поставщику компилятора также необходимо заменить компоновщик. Недостатками являются существенно возросшая сложность, а следовательно, потенциальные ошибки; для некоторых кодов это может быть столь же прозрачно, но на практике может быть очень сложно собрать несколько программ в одном каталоге и одну программу в нескольких каталогах. Код, написанный для этой модели, обычно отделяет определения нелинейных шаблонов членов в отдельный файл, который следует компилировать отдельно.

G++ реализует модель Borland на целевых платформах, где это поддерживается компоновщиком, включая ELF-целевые платформы (такие как GNU/Linux), macOS и Microsoft Windows. В противном случае G++ не реализует ни одну автоматическую модель.

У вас есть следующие варианты работы с экземпляризациями шаблонов:

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

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

    extern template int max (int, int);

    Этот синтаксис определён в стандарте C++ 2011, но поддерживается G++ и другими компиляторами с давних времён до 2011 года.

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

    #include "Foo.h"
    #include "Foo.cc"
    
    template class Foo<int>;
    template ostream& operator <<
                    (ostream&, const Foo<int>&);

    для каждого из необходимых экземпляров и создать библиотеку экземпляризации шаблонов из них.

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

  2. Скомпилируйте свой код с -fno-implicit-templates для отключения неявного создания экземпляризаций шаблонов и явно экземпляризируйте все используемые. Этот подход требует большего знания о том, какие именно экземпляризации необходимы, чем другие, но он менее загадочен и позволяет больше контроля, если вы хотите гарантировать, что используются только целевые экземпляризации.

    Если вы используете код модели Cfront, вы можете обойтись без использования -fno-implicit-templates при компиляции файлов, не включающих #include определений шаблонов членов.

    Если вы используете один большой файл для экземпляризации, вы можете скомпилировать его без -fno-implicit-templates, чтобы получить все экземпляризации, необходимые вашим явным экземпляризациям (но не другими файлами), без необходимости их указания.

    В дополнение к предварительному объявлению явных экземпляризаций (с extern), G++ расширил синтаксис экземпляризации шаблонов для поддержки экземпляризации данных поддержки компилятора для класса шаблона (например, vtable) без экземпляризации каких-либо его членов (с inline), и экземпляризации только статических данных членов класса шаблона без данных поддержки или функций-членов (с static):

    inline template class Foo<int>;
    static template class Foo<int>;

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Template-Instantiation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API