views:

1078

answers:

3

Suppose a header file defines a function template. Now suppose two implementation files #include this header, and each of them has a call to the function template. In both implementation files the function template is instantiated with the same type.

// 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);
}

One may expect the linker would complain about multiple definitions of f(). Specifically, if f() wouldn't be a template then that would indeed be the case.

  • How come the linker doesn't complain about multiple definitions of f()?
  • Is it specified in the standard that the linker must handle this situation gracefully? In other words, can I always count on programs similar to the above to compile and link?
  • If the linker can be clever enough to disambiguate a set of function template instantiations, why can't it do the same for regular functions, given they are identical as is the case for instantiated function templates?
+3  A: 

In order to support C++, the linker is smart enough to recognize that they are all the same function and throws out all but one.

EDIT: clarification: The linker doesn't compare function contents and determine that they are the same. Templated functions are marked as such and the linker recognizes that they have the same signatures.

Ferruccio
But not smart enough to recognize this when f() is not a template?
wilhelmtell
It's not allowed to, except for templates.
Head Geek
It does this for inline functions, too - if it decides not to inline them.
Mark Ransom
+1  A: 

This is more or less a special case just for templates.

The compiler only generates the template instantiations that are actually used. Since it has no control over what code will be generated from other source files, it has to generate the template code once for each file, to make sure that the method gets generated at all.

Since it's difficult to solve this (the standard has an extern keyword for templates, but g++ doesn't implement it) the linker simply accepts the multiple definitions.

CAdaker
+1  A: 

The Gnu C++ compiler's manual has a good discussion of this. An excerpt:

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.

cjm