Node: Template Instantiation, Next: Bound member functions, Previous: C++ Interface, Up: C++ Extensions
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 I will refer to as the Borland model and the Cfront model.
When used with GNU ld version 2.8 or later on an ELF system such as Linux/GNU or Solaris 2, or on Microsoft Windows, g++ supports the Borland model. On other systems, g++ implements neither automatic model.
A future version of g++ will support a hybrid model whereby the compiler will emit any instantiations for which the template definition is included in the compile, and store template definitions and instantiation context information into the object file for the rest. The link wrapper will extract that information as necessary and invoke the compiler to produce the remaining instantiations. The linker will then combine duplicate instantiations.
In the mean time, you have the following options for dealing with template instantiations:
-frepo
. The compiler will
generate files with the extension .rpo
listing all of the
template instantiations used in the corresponding object files which
could be instantiated there; the link wrapper, collect2
, will
then update the .rpo
files to tell the compiler where to place
those instantiations and rebuild any affected object files. The
link-time overhead is negligible after the first pass, as the compiler
will continue to place the instantiations in the same files.
This is your best option for application code written for the Borland
model, as it will just work. Code written for the Cfront model will
need to be modified so that the template definitions are available at
one or more points of instantiation; usually this is as simple as adding
#include <tmethods.cc>
to the end of each template header.
For library code, if you want the library to provide all of the template instantiations it needs, just try to link all of its object files together; the link will fail, but cause the instantiations to be generated as a side effect. Be warned, however, that this may cause conflicts if multiple libraries try to provide the same instantiations. For greater control, use explicit instantiation as described in the next option.
-fno-implicit-templates
to disable the
implicit generation of template instances, and explicitly instantiate
all the ones you use. This approach requires more knowledge of exactly
which instances you need than do the others, but it's less
mysterious and allows greater control. You can scatter the explicit
instantiations throughout your program, perhaps putting them in the
translation units where the instances are used or the translation units
that define the templates themselves; you can put all of the explicit
instantiations you need into one big file; or you can create small files
like
#include "Foo.h" #include "Foo.cc" template class Foo<int>; template ostream& operator << (ostream&, const Foo<int>&);
for each of the instances you need, and create a template instantiation library from those.
If you are using Cfront-model code, you can probably get away with not
using -fno-implicit-templates
when compiling files that don't
#include
the member template definitions.
If you use one big file to do the instantiations, you may want to
compile it without -fno-implicit-templates
so you get all of the
instances required by your explicit instantiations (but not by any
other files) without having to specify them as well.
g++ has extended the template instantiation syntax outlined in the
Working Paper to allow forward declaration of explicit instantiations
(with extern
), instantiation of the compiler support data for a
template class (i.e. the vtable) without instantiating any of its
members (with inline
), and instantiation of only the static data
members of a template class, without the support data or member
functions (with (static
):
extern template int max (int, int); inline template class Foo<int>; static template class Foo<int>;
#pragma interface
to all files containing template
definitions. For each of these files, add #pragma implementation
"
filename"
to the top of some .C
file which
#include
s it. Then compile everything with
-fexternal-templates
. The templates will then only be expanded
in the translation unit which implements them (i.e. has a #pragma
implementation
line for the file where they live); all other files will
use external references. If you're lucky, everything should work
properly. If you get undefined symbol errors, you need to make sure
that each template instance which is used in the program is used in the
file which implements that template. If you don't have any use for a
particular instance in that file, you can just instantiate it
explicitly, using the syntax from the latest C++ working paper:
template class A<int>; template ostream& operator << (ostream&, const A<int>&);
This strategy will work with code written for either model. If you are using code written for the Cfront model, the file containing a class template and the file containing its member templates should be implemented in the same translation unit.
-falt-external-templates
instead. This flag causes template
instances to be emitted in the translation unit that implements the
header where they are first instantiated, rather than the one which
implements the file where the templates are defined. This header must
be the same in all translation units, or things are likely to break.
See Declarations and Definitions in One Header, for more discussion of these pragmas.