The fact that instantiations are generated when a template is used (§ 16.1.1, p. 656) means that the same instantiation may appear in multiple object files. When two or more separately compiled source files use the same template with the same template arguments, there is an instantiation of that template in each of those files.
In large systems, the overhead of instantiating the same template in multiple files can become significant. Under the new standard, we can avoid this overhead through an explicit instantiation. An explicit instantiation has the form
extern template declaration; // instantiation declaration
template declaration; // instantiation definition
where declaration is a class or function declaration in which all the template parameters are replaced by the template arguments. For example,
// instantion declaration and definition
extern template class Blob<string>; // declaration
template int compare(const int&, const int&); // definition
When the compiler sees an extern
template declaration, it will not generate code for that instantiation in that file. Declaring an instantiation as extern
is a promise that there will be a nonextern
use of that instantiation elsewhere in the program. There may be several extern
declarations for a given instantiation but there must be exactly one definition for that instantiation.
Because the compiler automatically instantiates a template when we use it, the extern
declaration must appear before any code that uses that instantiation:
// Application.cc
// these template types must be instantiated elsewhere in the program
extern template class Blob<string>;
extern template int compare(const int&, const int&);
Blob<string> sa1, sa2; // instantiation will appear elsewhere
// Blob<int> and its initializer_list constructor instantiated in this file
Blob<int> a1 = {0,1,2,3,4,5,6,7,8,9};
Blob<int> a2(a1); // copy constructor instantiated in this file
int i = compare(a1[0], a2[0]); // instantiation will appear elsewhere
The file Application.o
will contain instantiations for Blob<int>
, along with the initializer_list
and copy constructors for that class. The compare<int>
function and Blob<string>
class will not be instantiated in that file. There must be definitions of these templates in some other file in the program:
// templateBuild.cc
// instantiation file must provide a (nonextern) definition for every
// type and function that other files declare as extern
template int compare(const int&, const int&);
template class Blob<string>; // instantiates all members of the class template
When the compiler sees an instantiation definition (as opposed to a declaration), it generates code. Thus, the file templateBuild.o
will contain the definitions for compare
instantiated with int
and for the Blob<string>
class. When we build the application, we must link templateBuild.o
with the Application.o
files.
There must be an explicit instantiation definition somewhere in the program for every instantiation declaration.
An instantiation definition for a class template instantiates all the members of that template including inline member functions. When the compiler sees an instantiation definition it cannot know which member functions the program uses. Hence, unlike the way it handles ordinary class template instantiations, the compiler instantiates all the members of that class. Even if we do not use a member, that member will be instantiated. Consequently, we can use explicit instantiation only for types that can be used with all the members of that template.