Вопрос

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

// header.hh
template <typename T>
void f(const T& o)
{
    // ...
}

// impl1.cc
#include "header.hh"

void fimpl1()
{
    f(42);
}

// impl2.cc
#include "header.hh"

void fimpl2()
{
    f(24);
}

Можно ожидать, что компоновщик будет жаловаться на несколько определений f().В частности, если f() это не было бы шаблоном, тогда это действительно было бы так.

  • Почему компоновщик не жалуется на несколько определений f()?
  • Указано ли в стандарте, что компоновщик должен корректно обрабатывать эту ситуацию?Другими словами, могу ли я всегда рассчитывать на компиляцию и компоновку программ, подобных приведенным выше?
  • Если компоновщик может быть достаточно умен, чтобы устранить неоднозначность набора экземпляров шаблонов функций, почему он не может сделать то же самое для обычных функций, учитывая, что они идентичны, как и в случае с экземплярами шаблонов функций?
Это было полезно?

Решение

Чтобы поддерживать C++, компоновщик достаточно умен, чтобы распознать, что все они представляют собой одну и ту же функцию, и отбрасывает все, кроме одной.

РЕДАКТИРОВАТЬ:уточнение:Компоновщик не сравнивает содержимое функций и не определяет, что они одинаковы.Шаблонные функции помечаются как таковые, и компоновщик распознает, что они имеют одинаковые сигнатуры.

Другие советы

В руководстве компилятора Gnu C++ есть хорошее обсуждение этого.Отрывок:

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

Модель Борланда

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

Передняя модель

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

При использовании с GNU LD версией 2.8 или более поздней версии в системе ELF, такой как GNU/Linux или Solaris 2, или на Microsoft Windows, G ++ поддерживает модель Borland.В других системах G ++ не реализует ни автоматической модели.

Это более или менее частный случай только для шаблонов.

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

Так как решить это сложно (в стандарте есть extern ключевое слово для шаблонов, но g++ его не реализует) компоновщик просто принимает несколько определений.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top