Предположим, что файл заголовка определяет шаблон функции. Теперь предположим, что это два файла реализации #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()?Я уточнил вопрос. Это довольно широкий вопрос, поэтому я разделил его на более мелкие вопросы. Возможно, мне следует разделить их на несколько ТАКИХ вопросов?
Я не вижу "множественных определений" f () в вашем коде.





Для поддержки C++ компоновщик достаточно умен, чтобы распознать, что все они являются одной и той же функцией, и выбрасывает все, кроме одной.
Обновлено: пояснение: Компоновщик не сравнивает содержимое функций и не определяет, что они одинаковы. Шаблонные функции помечаются как таковые, и компоновщик распознает, что у них одинаковые подписи.
Но недостаточно умен, чтобы распознать это, когда f () не является шаблоном?
Не разрешено, кроме шаблонов.
Он делает это и для встроенных функций - если он решает не встраивать их.
Это более-менее частный случай только для шаблонов.
Компилятор создает только фактически используемые экземпляры шаблона. Поскольку он не контролирует, какой код будет сгенерирован из других исходных файлов, он должен сгенерировать код шаблона один раз для каждого файла, чтобы убедиться, что метод вообще сгенерирован.
Поскольку это сложно решить (в стандарте есть ключевое слово extern для шаблонов, но g ++ не реализует его), компоновщик просто принимает несколько определений.
В руководстве компилятора Gnu C++ есть хорошее обсуждение этого. Отрывок:
C++ templates are the first language feature to require more intelligence from the environment than one usually finds on a UNIX system. Somehow the compiler and linker have to make sure that each template instance occurs exactly once in the executable if it is needed, and not at all otherwise. There are two basic approaches to this problem, which are referred to as the Borland model and the Cfront model.
Borland model
Borland C++ solved the template instantiation problem by adding the code equivalent of common blocks to their linker; the compiler emits template instances in each translation unit that uses them, and the linker collapses them together. The advantage of this model is that the linker only has to consider the object files themselves; there is no external complexity to worry about. This disadvantage is that compilation time is increased because the template code is being compiled repeatedly. Code written for this model tends to include definitions of all templates in the header file, since they must be seen to be instantiated.
Cfront model
The AT&T C++ translator, Cfront, solved the template instantiation problem by creating the notion of a template repository, an automatically maintained place where template instances are stored. A more modern version of the repository works as follows: As individual object files are built, the compiler places any template definitions and instantiations encountered in the repository. At link time, the link wrapper adds in the objects in the repository and compiles any needed instances that were not previously emitted. The advantages of this model are more optimal compilation speed and the ability to use the system linker; to implement the Borland model a compiler vendor also needs to replace the linker. The disadvantages are vastly increased complexity, and thus potential for error; for some code this can be just as transparent, but in practice it can be very difficult to build multiple programs in one directory and one program in multiple directories. Code written for this model tends to separate definitions of non-inline member templates into a separate file, which should be compiled separately.
When used with GNU ld version 2.8 or later on an ELF system such as GNU/Linux or Solaris 2, or on Microsoft Windows, G++ supports the Borland model. On other systems, G++ implements neither automatic model.
Заголовок вводит в заблуждение ... а как насчет "множественных экземпляров"? Или «экземпляры в отдельных единицах перевода»?