Несколько определений шаблона функции - PullRequest
10 голосов
/ 25 октября 2008

Предположим, что заголовочный файл определяет шаблон функции. Теперь предположим два файла реализации #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()?
  • В стандарте указано, что компоновщик должен корректно обрабатывать эту ситуацию? Другими словами, могу ли я всегда рассчитывать на программы, аналогичные приведенным выше, для компиляции и компоновки?
  • Если компоновщик может быть достаточно умным для устранения неоднозначности набора экземпляров шаблона функции, почему он не может сделать то же самое для обычных функций, если они идентичны, как в случае с экземплярами шаблонов функций?

Ответы [ 3 ]

5 голосов
/ 25 октября 2008

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

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

4 голосов
/ 25 октября 2008

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

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

Borland модель

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

Модель фронта

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

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

1 голос
/ 25 октября 2008

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

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

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

...