Chapter 4. Using Templates

The information in this chapter is derived from the C++ Front End Internal Documentation, Version 2.45, copyright 1992-2000, by the Edison Design Group. Used by the permission of the authors.

Template Instantiation

The C++ programming language includes the concept of templates . A template is a description of a class or function that is a model for a family of related classes or functions. Because templates are descriptions of entities (typically, classes) that are parameterizable according to the types they operate upon, they are sometimes called parameterized types. For example, you can write a template for a Stack class and then use a stack of integers, a stack of floats, and a stack of a user-defined type. In the source code, these might be written as follows:

Stack<int>
Stack<float>
Stack<X>

From a single source description of the template for a stack, the compiler can create an instantiation of the template for each of the types that is required.

The instantiation of a class template is done as soon as it is needed in a compilation. However, the instantiations of template functions, member functions of template classes, and static data members of template classes (hereafter referred to as template entities) are not necessarily done immediately for the following reasons:

  • You should have only one copy of each instantiated entity across all the object files that make up a program. (This applies to entities with an external linkage.)

  • You can write a specialization of a template entity. (For example, you can write a version either of Stack<int>, or of just Stack<int>::push, that replaces the template-generated version. Often, this kind of specialization provides a more efficient representation for a particular data type.) When compiling a reference to a template entity, the compiler does not know if a specialization for that entity will be provided in another compilation. Therefore, the compiler cannot do the instantiation automatically in any source file that references it.

  • You cannot compile template functions that are not referenced. Such functions might contain semantic errors that would prevent them from being compiled. A reference to a template class should not automatically instantiate all the member functions of that class.


Note: Certain template entities are always instantiated when used (for example, inline functions).

If the compiler is responsible for doing all the instantiations automatically, it can do so only on a program-wide basis. The compiler cannot make decisions about instantiation of template entities until it has seen all the source files that make up a complete program.

By default, CC performs automatic instantiation at link time. If more explicit control is needed, instantiation modes and instantiation pragmas are also provided and can be used to provide fine-grained control over the instantiation process.

The following subsections discuss methods of instantiation and other associated topics.

Automatic Instantiation

Automatic instantiation enables you to compile source files to object code, link them, run the resulting program, and never worry about how the necessary instantiations are done.

The CC(1) command requires that for each instantiation you have a normal, top-level, explicitly compiled source file that contains the definition of the template entity, a reference that causes the instantiation, and declarations of any types required for the particular instantiation.

Meeting Instantiation Requirements

You can meet the instantiation requirements in several ways:

  • You can have each header file that declares a template entity contain either the definition of the entity or another file that contains the definition.

  • When the compiler encounters a template declaration in a header file and discovers a need to instantiate that entity, you can give it permission to search for an associated definition file having the same base name and a different suffix. The compiler implicitly includes that file at the end of the compilation. See “Implicit Inclusion” for more information.

  • You can make sure that the files that define template entities also have the definitions of all the available types, and add code or #pragma directives in those files to request instantiation of the entities they contain.

Automatic Instantiation Method

The following steps outline the general process for using automatic instantiation.

  1. The first time the source files of a program are compiled, no template entities are instantiated. However, template information files (with a default .ti suffix) are generated and contain information about things that could have been instantiated in each compilation.

  2. When the object files are linked together, a program called the prelinker is run. It examines the object files, looking for references and definitions of template entities, and for the added information about entities that could be instantiated.

  3. If the prelinker finds a reference to a template entity for which there is no definition anywhere in the set of object files, it looks for a file that indicates that it could instantiate that template entity. When it finds such a file, it assigns the instantiation to it. The set of instantiations assigned to a given file (for example, abc.C) is recorded in an associated .ii file (for example, abc.ii). All .ii files are stored in a directory named ii_files created within your object file directory.

  4. The prelinker then executes the compiler again to recompile each file for which the .ii file was changed. The original compilation command-line options (saved in the information file) are used for the recompilation.

  5. When a file is compiled, the compiler reads the .ii file for that file and obeys the instantiation requests therein. It produces a new object file containing the requested template entities (and all the other things that were already in the object file). The compiler also receives a definition list file, which lists all the instantiations for which definitions already exist in the set of object files. If during compilation the compiler has the opportunity to instantiate a reference entity that is not on that list, it goes ahead and does the instantiation. It passes back to the prelinker (in the definition list file) a list of the instantiations that it has 'adopted' in this way, so the prelinker can assign them to the file. This 'adoption' process allows rapid instantiation and assignment of instantiations referenced from new instantiations, and reduces the need to recompile a given file more than once during the prelinking process.

  6. The prelinker repeats steps 3-5 until there are no more instantiations to be adjusted.

  7. The object files are linked.

After the program has been linked correctly, the .ii files contain a complete set of instantiation assignments. From then on, whenever source files are recompiled, the compiler will consult the .ii files and do the indicated instantiations as it does the normal compilations. Except in cases where the set of required instantiations changes, the prelink step will find that all the necessary instantiations are present in the object files and that no instantiation assignment adjustments need be done. This is true even if the entire program is recompiled.

If you provide a specialization of a template entity somewhere in the program, the specialization will be seen as a definition by the prelinker. Becasue that definition satisfies whatever references there might be to that entity, the prelinker sees no need to request an instantiation of the entity. If you add a specialization to a program that has previously been compiled, the prelinker notices that, too, and removes the assignment of the instantiation from the proper .ii file.

The .ii files should not, in general, require any manual intervention. The only exception is if the following conditions are met:

  • A definition is changed in such a way that some instantiation no longer compiles. (It generates errors.)

  • A specialization is simultaneously added in another file.

  • The first file is recompiled before the specialization file and is generating errors.

The .ii file for the file generating the errors must be deleted manually to allow the prelinker to regenerate it.

If the prelinker changes an instantiation assignment, it will issue a message, such as the following:

C++ prelinker: A<int>::f() assigned to file test.o
C++ prelinker: executing: usr/lib/edg-prelink -c test.c

The automatic instantiation scheme can coexist with partial explicit control of instantiation by the programmer, through the use of #pragma directives or command-line specification of the instantiation mode as described in the following subsections.

Instantiations are normally generated as part of the object file of the translation unit in which the instantiations are performed. But when 'one instantiation per object' mode is specified, each instantiation is placed in its own object file. One-instantiation-per-object mode is useful when generating libraries that need to include copies of the instances referenced from the library. If each instance is not placed in its own object file, it may be impossible to link the library with another library containing some of the same instances. Without this feature it is necessary to create each individual instantiation object file using the manual instantiation mechanism.

The automatic instantiation mode can be disabled by using the -no_prelink option.

If automatic instantiation is turned off, the following conditions are true:

  • The extra information about template entities that could be instantiated in a file is not put into the object file.

  • The .ii file is not updated with the command line.

  • The prelinker is not invoked.

Instantiation Modes

Normally, when a file is compiled, no template entities are instantiated (except those assigned to the file by automatic instantiation). The overall instantiation mode can, however, be changed by a command line option.

You can use command-line options to control the instantiation behavior of the compiler. These options are divided into four sets of related options, as shown in the following list. You use one option from each category: options from the same category are not used together. For example, you cannot specify -ptnone in conjunction with -ptused.

  • -ptnone (the default), -ptused , or -ptall. (Automatic template instantiation should make the use of -ptused or -ptall unnecessary in most cases.)

  • -prelink (the default) or -no_prelink

  • -auto_include or -no_auto_include

  • -ptv

The following command line options control instantiation behavior of the compiler:

-ptnone
 

None of the template entities are instantiated. If automatic instantiation is turned on (in other words, -prelink), any template entities that the prelinker instructs the compiler to instantiate are instantiated.

-ptused
 

Any template entities used in this compilation unit are instantiated. This includes all static members that have template definitions. If you specify -ptused, automatic instantiation is turned off by default. If you enable automatic instantiation explicitly (with -prelink), any additional template entities that the prelinker instructs the compiler to instantiate are also instantiated.

-ptall
 

Any template entities declared or referenced in the current compilation unit are instantiated. For each fully instantiated template class, all its member functions and static data members are instantiated whether or not they are used.


Note: The use of the -ptall option is being deprecated in the MIPSpro compilers.

Nonmember template functions are instantiated even if the only reference was a declaration. If you specify -ptall, automatic instantiation is turned off by default. If you enable automatic instantiation explicitly (with -prelink), any additional template entities that the prelinker instructs the compiler to instantiate are also instantiated.

-prelink
 

Instructs the compiler to output information from the object file and an associated .ii file to help the prelinker determine which files should be responsible for instantiating the various template entities referenced in a set of object files.

When -prelink is on, the compiler reads an associated .ii file to determine if any template entities should be instantiated. When -prelink is on and a link is being performed, the compiler calls a template prelinker. If the prelinker detects missing template entities, they are assigned to files (by updating the associated .ii file), and the prelinker recompiles the necessary source files.

-no_prelink
 

Disables automatic instantiation. Instructs the compiler to not read a .ii file to determine which template entities should be instantiated. The compiler will not store any information in the object file about which template entities could be instantiated. This option also directs the compiler to not invoke the template prelinker at link time.

This is the default mode if -ptused or -ptall is specified.

-auto_include
 

Instructs the compiler to implicitly include template definition files if such definitions are needed. (See “Implicit Inclusion”.)

-no_auto_include
 

Disables implicit inclusion of template implementation files.

-ptv
 

Puts the template prelinker in verbose mode; when a template entity is assigned to a particular source file, the name of the template entity and source file is printed.


Note: In the case where a single file is compiled and linked, the compiler uses the -ptused option to suppress automatic instantiation.


Command Line Instantiation Examples

This section provides you with typical combinations of command line instantiation options, along with an explanation of what these combinations do and how they may be used.

Although there are many possible combinations of options, the following are the most common combinations:

-ptnone, -prelink, -auto_include
 

This is the default mode, which is suitable for most applications. On the first build of an application, the prelinker determines which source files should instantiate the necessary template entities. On subsequent rebuilds, the compiler automatically instantiates the template entities.

-ptused
 

This mode is suitable for small- and medium-sized applications. No prelinker pass is necessary. All referenced template entities are instantiated at compile time. Dynamically initialized static data members are also handled correctly (by using a run-time guard to prevent duplicate initialization of such members).

-ptused, -prelink
 

Use this combination when you have an archive or dynamic shared object (DSO) that has not been prelinked.

When a DSO is built, it is automatically prelinked. When an archive is built, it is recommended that you run the prelinker on the object files before archiving them. However, there are cases where you may choose not to do so.

For example, if an application is linked using multiple internal DSOs or archives, then you may choose not to prelink each DSO or archive, since that may create multiple instances of some template entities. When building an application using such archives or DSOs, you should use -prelink at compile time, even if the application is being built using -ptused. This is because the object files must contain not only instances of template entities referenced in the compilation units, but also instances of template entities referenced in archives and DSOs.

-ptall, -no_prelink
 

Use this combination when you are building a library of instantiated templates.

For example, consider if you implement a stack template class containing various member functions. You may choose to provide instantiated versions of these functions for various common types (such as, int and float) and the easiest way of instantiating all member functions of a template is to specify -ptall.

-ptnone, -no_prelink
 

Use this combination if you are using template entities that are pre-instantiated.

For example, suppose you are using templates and know that all of your referenced template entities have already been pre-instantiated in a library such as one described in the previous example. In this case, you do not need any templates instantiated at compile time, and you should turn off automatic instantiation.

-auto_include
 

Use this option if you are using template implementation files that are not explicitly included.

-no_auto_include
 

Use this option if you are using only template implementation files that are explicitly included.

Source code written for compilers such as Borland C++ includes all necessary template implementation files. Such source code should be compiled with the -no_auto_include option.

#pragma Directives for Template Instantiation

You can use #pragma directives to control the instantiation of individual or sets of template entities. There are three instantiation #pragma directives:

#pragma instantiate

The #pragma instantiate directive causes a specific instance of a template declaration to be immediately instantiated.

The syntax of the #pragma instantiate directive is as follows:

#pragma instantiate   entity   

The entity argument can be any of the following:

A template class name
 

A<int>

A member function name
 

A<int>::foo

A member function declaration
 

void A<int>::foo(int, char)

A static data member name
 

A<int>::name

A template function declaration
 

char* foo(int, float)

The template definition of entity must be present in the compilation for an instantiation to occur. If you use #pragma instantiate to explicitly request the instantiation of a class or function for which no template definition is available, the compiler issues a warning.

The declaration needs to be a complete declaration of a function or a static data member, exactly as if you had specified it for a specialization of the template.

The argument to an instantiation #pragma directive cannot be a compiler-generated function, an inline function, or a pure virtual function.

A member function name (for example, A<int>::foo) can be used as an argument for a #pragma instantiate directive only if it refers to a single, user-defined member function that is not an overloaded function. Compiler-generated functions are not considered, so a name can refer to a user-defined constructor even if a compiler-generated copy constructor of the same name exists. Overloaded member functions can be instantiated by providing the complete member function declaration, as the following example shows:

char * A<int>::foo(int)) 


Note: Using the #pragma instantiate directive to instantiate a template class is equivalent to repeating the directive for each member function and static data member declared in the class. When instantiating an entire class, you can exclude a given member function or static data member by using the #pragma do_not_instantiate directive.


#pragma can_instantiate

The #pragma can_instantiate directive indicates that the specified entity can be instantiated in the current compilation, but need not be. It is used in conjunction with automatic instantiation to indicate potential sites for instantiation if the template entity is deemed to be required by the compiler.

The syntax of the #pragma can_instantiate directive is as follows:

#pragma can_instantiate entity   

The argument, entity, can be any of the following:

A template class name
 

A<int>

A member function name
 

A<int>::foo

A member function declaration
 

void A<int>::foo(int, char)

A static data member name
 

A<int>::name

A template function declaration
 

char* foo(int, float)

The template definition of entity must be present in the compilation for an instantiation to occur. If you use #pragma can_instantiate to explicitly request the instantiation of a class or function for which no template definition is available, the compiler issues a warning.

The argument to a #pragma can_instantiate directive cannot be a compiler-generated function, an inline function, or a pure virtual function.

A member function name (for example, A<int>::foo) can be used as an argument for a #pragma can_instantiate directive only if it refers to a single, user-defined member function that is not an overloaded function. Compiler-generated functions are not considered, so a name can refer to a user-defined constructor even if a compiler-generated copy constructor of the same name exists. Overloaded member functions can be instantiated by providing the complete member function declaration, as shown in the following example:

char * A<int>::foo(int) 

#pragma do_not_instantiate

The #pragma do_not_instantiate directive suppresses the instantiation of a specified entity. It is typically used to suppress the instantiation of an entity for which a specific definition is supplied.

The syntax of the #pragma do_not_instantiate directive is as follows:

#pragma do_not_instantiate entity   

The argument, entity, can be any of the following:

A template class name
 

A<int>

A member function name
 

A<int>::foo

A member function declaration
 

void A<int>::foo(int, char)

A static data member name
 

A<int>::name

A template function declaration
 

char* foo(int, float)

The argument to a #pragma do_not_instantiate directive cannot be a compiler-generated function, an inline function, or a pure virtual function.

A member function name (for example, A<int>::foo) can be used as an argument for the #pragma do_not_instantiate directive only if it refers to a single, user-defined member function that is not overloaded. Compiler-generated functions are not considered, so a name can refer to a user-defined constructor even if a compiler-generated copy constructor of the same name exists. Overloaded member functions can be specified by providing the complete member function declaration, as the following example shows:

char * A<int>::foo(int) 

Implicit Inclusion

When implicit inclusion is enabled, the compiler assumes that if it needs a definition to instatiate a template entity declared in a .h file, it can implicitly include the corresponding .C file to get the source code for the definition. For example, if a template entity ABC::f is declared in file xyz.h, and an instantiation of ABC::f is required in a compilation but no definition of ABC::f appears in the source code processed by the compilation, the compiler looks to see if a file xyz.C exists, and if so it will process it as if it were included at the end of the main source file.

To find the template definition file for a given template entity the compiler needs to know the full path name of the file in which the template was declared and whether the file was included using the system include syntax (that is, #include <file.h>). This information is not available for preprocessed source containing #line directives. Therefore, the compiler does not attempt implicit inclusion for source code containing #line directives.

The definition-file suffixes that are tried are the following:

.c
.C
.cpp
.CPP
.cxx
.CXX
.cc
.CC
.c++
.C++

Implicit inclusion works well with automatic instantiation but the two are independent. They can be enabled or disabled independently, and implicit inclusion is still useful when automatic instantiation is not done.

Implicit inclusions are only performed during the normal compilation of a file (that is, not when doing only preprocessing). A common means of investigating certain kinds of problems is to produce a preprocessed source file that can be inspected. When using implicit inclusion it is sometimes desirable for the preprocessed source file to include any implicitly included files. This may be done using the -FE:generate_preprocessed_output command line option. This causes the preprocessed output to be generated as part of a normal compilation. When implicit inclusion is being used, the implicitly included files will appear as part of the preprocessed output in the precise location at which they were included in the compilation.