This chapter discusses the Silicon Graphics C++ implementation of templates. It compares the Silicon Graphics implementation to those of the BorlandŽ C++ and cfront compilers. It contains the following major sections:
“CC -32 Template Instantiation” describes how you perform template instantiation in the 32-bit Silicon Graphics C++ environment.
“CC -64 Template Instantiation” describes how you perform template instantiation in the 64-bit Silicon Graphics C++ environment.
“How to Transition From cfront” describes how a programmer currently using the cfront template instantiation mechanism can transition to the template instantiation scheme used by the new Silicon Graphics C++ compilers.
“Template Language Support” describes how template language is supported in the Silicon Graphics C++ environment.
cfront template support is discussed in the chapter “Automatic Template Instantiation” in the C++ Language System Overview.
This section describes the 32-bit implementation of templates.
The instantiation of a class template is always 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. The reasons for this are given below.
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 external linkage.)
You may write a specialization of a template entity. (For example, you can write a version of Stack<int>, or of just Stack<int>::push, that replaces the template-generated version. Often, this kind of specialization is 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. The compiler cannot do the instantiation automatically in any source file that references it.
You may not 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 -32 performs automatic instantiation at link time. It is also possible for you to instantiate all necessary template entities at compile time using the -ptused option. See “Explicit Instantiation” for further details.
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.
CC -32 requires that for each instantiation you have a normal, top-level, explicitly-compiled source file that contains both the definition of the template entity and any types required for the particular instantiation.
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 sees 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. This method allows most programs written using the cfront convention to be compiled. See “Implicit Inclusion”.
You can make sure that the files that define template entities also have the definitions of all the available types, and add code or pragmas in those files to request instantiation of the entities there.
The first time the source files of a program are compiled, no template entities are instantiated. However, the generated object files contain information about things that could have been instantiated in each compilation.
When the object files are linked, 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.
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, say 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 below your object file directory.
The prelinker then executes the compiler again to recompile each file for which the .ii file was changed. (The .ii file contains enough information to allow the prelinker to determine which options should be used to compile the same file.)
When the compiler compiles a file, it 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 prelinker repeats steps 3-5 until there are no more instantiations to be adjusted.
The object files are linked.
Once 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. Since that definition satisfies whatever references there might be to that entity, the prelinker will see no need to request an instantiation of the entity. If the programmer adds a specialization to a program that has previously been compiled, the prelinker will notice that too and remove 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 conditions below are all 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:
C++ prelinker: f__10A__pt__2_iFv assigned to file test.o C++ prelinker: executing: usr/lib/DCC/edg-prelink -c test.c |
The name in the message is the mangled name of the entity. These messages are printed if you use the -ptv option.
The automatic instantiation scheme can coexist with partial explicit control of instantiation by the programmer, through the use of pragmas or command-line specification of the instantiation mode.
The automatic instantiation mode can be disabled by using the -no_prelink option.
If automatic instantiation is turned off,
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
For the best results, you must include all the template implementation files in your source files. Since most cfront users do not do this, the compiler attempts to find unincluded template bodies automatically. For example, suppose that the following conditions are all true.
template entity ABC::f is declared in file xyz.h
an instantiation of ABC::f is required in a compilation
no definition of ABC::f appears in the source code processed by the compilation
In this case, the compiler looks to see if the source file xyz.n exists. (By default, the list of suffixes tried for n is .c, .C, .cpp, .CPP, .cxx, .CXX, and .cc.) If so, the compiler processes it as if it were included at the end of the main source file.
Implicit inclusion works well alongside 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 inclusion can be disabled with the -no_auto_include option.
CC -32instantiates all templates at compile time if you use the -ptused option. The compiler produces larger object files because it stores duplicate instantiations in the object files. The duplicate copies are removed by the linker, and do not exist in the final executables.
The CC -32 template instantiation mechanism also correctly handles static data members when you use the -ptused option. Static data members that need to be dynamically initialized may be instantiated in multiple compilation units. However, the dynamic initialization takes place only once. This is implemented by using a flag which is set the first time a static data member is initialized. This flag prevents further attempts to initialize it dynamically.
The -ptused option is acceptable for most small- or medium-sized applications. There are some drawbacks listed below:
Instantiating everything produces large object files.
Although duplicate code is removed, the associated debug information is not removed, producing large executables.
If you change a template body, you must recompile every file that contains an instantiation of this body. (The easiest way to do this is for you to use make in conjunction with the -MDupdate option. See the DCC(1) reference page and “Limitations” for more information.)
If you plan on specializing a template function instantiation, you may have to set #pragma do_not_instantiate if it is likely that the compiler-generated instantiation will contain syntax errors.
Data is not removed, so there are multiple copies of static data members.
You can exercise finer control over exactly what is instantiated in each object file by using pragmas and command-line options.
You may use command-line options to control the instantiation behavior of the compiler. These options are divided into sets of related options, as shown below. You use one option from each category; options from the same category are not used together. (For example, you do not use -ptnone in conjunction with -ptused.)
-ptnone (the default), -ptused, and -ptall
-prelink (the default) and -no_prelink
-auto_include, -no_auto_include
-ptv
The command line options are listed below.
| -ptnone | None of the template entities are instantiated. If automatic instantiation is 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. Nonmember template functions are instantiated even if the only reference was a declaration. If you use -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 driver 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 | 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 driver not to invoke the template prelinker at link time. This is the default mode if -ptused or -ptall are specified. | |
| -auto_include | Instructs the compiler to implicitly include template definition files if such definitions are needed. (See “Implicit Inclusion”.) | |
| -no_auto_include |
| |
| -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. |
This section provides you with combinations of command line instantiation that you may want to use, along with an explanation of what these combinations would do, and what you might use them for.
Although there are many possible combinations of options, the most common are listed below:
| -ptnone -prelink -auto_include |
| |
| -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, and the linker removes duplicate functions. Dynamically initialized static data members are also handled correctly (by using a runtime guard to prevent duplicate initialization of such members). | |
| -ptused -prelink | When a DSO is built, it is automatically prelinked. When an archive is built, we recommend that you run the prelinker on the object files before archiving them. However, there are cases where a programmer 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 templates instances referenced in the compilation units, but also instances of template entities referenced in archives and DSOs. | |
| -ptall -no_prelink |
For example, consider if you have a “stack” template class containing various member functions. You may choose to provide instantiated versions of these functions for various common types (for example, int, float, and so on) and the easiest way of instantiating all member functions of a template is to use -ptall. | |
| -ptnone -no_prelink |
For example, suppose you are using templates, but know that all of your referenced template entities have already been pre-instantiated in a library such as 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 |
Most source code written for cfront style compilers does not usually include template implementation files, because the cfront prelinker does this automatically. The -auto_include option is the default mode, because you want to compile cfront style code, but still instantiate templates at compile time (which implies finding template implementation files automatically). | |
| -no_auto_include |
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. | |
| -ptnone -no_prelink |
By using these options, you guarantee that nothing will be instantiated unless an explicit pragma is provided. |
You can use pragmas to control the instantiation of individual or sets of template entities. There are three instantiation pragmas:
| instantiate | Causes a specified entity to be instantiated. | |
| do_not_instantiate |
| |
| can_instantiate | Allows (but does not force) a specified entity to be instantiated in the current compilation. You can use it in conjunction with automatic instantiation to indicate potential sites for instantiation if the template entity turns out to be required. |
The arguments to the instantiation pragma may be
a template class name, such as A<int>
a member function name, such as A<int>::f
a static data member name, such as A<int>::i
a member function declaration, such as void A<int>::f(int, char)
a template function declaration, such as char* f(int, float)
A pragma directive in which the argument is a template class name (for example, A<int>) is the same as repeating the pragma for each member function and static data member declared in the class.
When you instantiate an entire class, you may exclude a given member function or static data member using the do_not_instantiate pragma. See the example below:
#pragma instantiate A<int> #pragma do_not_instantiate A<int>::f |
You must present the template definition of a template entity in the compilation for an instantiation to occur. (You can also find the template entity with implicit inclusion.) If you request an instantiation by using the instantiate pragma and no template definition is available or a specific definition is provided, you will receive a link-time error. For example:
template <class T> void f1(T);
template <class T> void g1(T);
void f1(int) {}
void main()
{
int i;
double d;
f1(i);
f1(d);
g1(i);
g1(d);
}
#pragma instantiate void f1(int)
#pragma instantiate void g1(int)
|
f1(double) and g1(double) are not instantiated (because no bodies were supplied) but no errors are produced during the compilation. If no bodies are supplied at link time, you will receive a linker error.
You can use a member function name (for example, A<int>::f) as a pragma argument only if it refers to a single user-defined member function. (In other words, not an overloaded function.) Compiler-generated functions are not considered, so a name may refer to a user-defined constructor even if a compiler-generated copy constructor of the same name exists.
You can instantiate overloaded member functions by providing the complete member function declaration. See the example below:
#pragma instantiate char* A<int>::f(int, char*) |
The argument to an instantiation pragma may not be a compiler-generated function, an inline function, or a pure virtual function.
CC -32 supports specialization. In template instantiation, you specialize when you define a specific version of a function or static data member.
Because the compiler instantiates everything at compile time when the –ptused option is specified, a specialization is not seen until link time. The linker and runtime loader select the specialization over any non-specialized versions of the function or static data member.
See “Pragmas for Template Instantiation” for information on how to suppress the instantiation of a function. You may find this useful if you intend to provide a specialization in another object file and the non-specialized version cannot be instantiated.
When you build a shared library or archive, you should usually instantiate any template instances that could be needed.
The prelinker is automatically run when building a shared library, but it must be run manually when building an archive. Follow the steps below to build your archive.
Enter the command /usr/lib/DCC/edg_prelink a.o b.o
This instantiates any templates needed by these object files.
Enter the command ar cr libtest.a a.o b.o to build the archive.
There are some limitations on template instantiation in the Silicon Graphics C++ environment:
A template specialization that exists in an archive may fail to be selected.
If you define a specialization within an object file that exists in an archive, and that object file does not satisfy any references (other than the reference to the specialization), then the object file is not selected. Any function generated from a template that appears before the archive will be used, although a specialization should take precedence over a generated function.
The following conditions have to be present for the bug to occur:
A template member needs to be specialized.
The specialization must live in an archive element.
A non-specialization of the template member must live in an object file seen by the linker. For a non-specialization to live in an object file, -ptused must have been specified (in other words, not the default mode).
Nothing else that exists in the archive element is referenced; that is, the specialization is probably the only thing in the object file.
You can use either of the following two workarounds:
Force the archive element to be loaded by defining some dummy global within it, and passing the -u option to the linker to force an undefined reference to the dummy global.
Use a .so (that is, a dynamic shared object) instead of an archive. The runtime loader will correctly select specializations from dynamic shared objects.
There is no link time mechanism to detect changes in template implementation files or to re-instantiate those template bodies that are out of date when you use the -ptused option.
Since Makefiles usually makes object files dependent on the .h files where templates are defined, make may not enable you to rebuild the right set of object files if you modify a template implementation file. To make sure you rebuild all files that instantiate a given template when the template body changes, you must follow the steps below.
Use the -MDupdate option at compile time to update a dependency file (usually called Makedepend). The compiler lists dependencies for all applicable #include files, including template implementation files that are implicitly included.
Make sure that your Makefile includes this dependency file. See the DCC(1) and make reference pages for more information on how to include files within a Makefile.
The only object files that the prelinker can recompile are object files that have not been renamed after they were originally compiled. In particular, the following limitations apply:
The prelinker cannot recompile any object file that exists in an archive, since putting an object file in an archive is equivalent to renaming it. It is recommended that you run the prelinker on object files before putting them in an archive. A similar restriction applies to dynamic shared objects (see “Building Shared Libraries and Archives”).
The prelinker cannot compile an object file if it was renamed after being compiled. For example, consider the following command line:
yacc gram.y CC -32 -c y.tab.c mv y.tab.o object.o |
The prelinker does not know how to recompile object.o. If object.o contains unresolved template references that will not be satisfied by any other objects, you must use the -ptused option when compiling, or explicitly invoke the prelinker on the object file before moving it.
The instantiation method for CC -64 is somewhat different from that of CC -32. CC -64 currently does not support automatic template instantiation. The CC -32 options for template instantiation are not recognized by CC -64; instead, it behaves as if the options -ptused -no_prelink -no_auto_include had been selected. That is, the following is true:
Any template entities used in a compilation unit are instantiated. This works much as the -ptused option, described in “Command Line Options for Template Instantiation”.
Pragmas to control the instantiation are supported.
There is no implicit inclusion of template definition files.
If you plan on specializing a template function instantiation, you must set #pragma do_not_instantiate if it is likely that the compiler-generated instantiation will contain syntax errors.
The prelink mechanism is not supported.
The associated .ii files are not created or used.
If you have compiled your source code with cfront, you may have to modify your build scripts to ensure that your templates are instantiated properly. This section discusses how to transition templates from cfront to the Silicon Graphics environment.
The cfront template-related options, their meaning, and the equivalent CC -32 options are listed below:
| -pta | Instantiates a whole template class rather than only those members that are needed. If you use automatic instantiation, there is no equivalent option for CC -32. If you use explicit instantiation, the -ptall option performs roughly the same action. | ||
| -pte suffix | Uses suffix as the standard source suffix instead of .c. There is currently no equivalent CC -32 option. CC -32 always looks for the following suffixes when looking for a template body to implicitly include: .c, .C, .cpp, .CPP, .cxx, .CXX, .cc, .c++. | ||
| -ptn | Changes the default instantiation behavior for one-file programs to that of larger programs, where instantiation is broken out separately and the repository updated. One-file programs normally have instantiation optimized so that instantiation is done into the application object itself. There is currently no equivalent CC -32 option. One way of approximating this behavior is to compile your file with -c, and then link it, instead of compiling and linking in a single step. Another method is to create an empty dummy file, and compile/link your original file and the new dummy file in a single step. For example, you can use the following command line:
| ||
| -ptrpathname | Specifies a repository, with ./ptrepository as the default. If several repositories are given, only the first is writable, and the default repository is ignored unless explicitly named. There is no equivalent option for CC -32. The cfront “repositories” contain two kinds of information:
The CC -32 template instantiation mechanism does not use separate object files for template instantiations; all necessary template instantiations are performed in files that are part of the application (or library) being built. Information about which templates are capable of being instantiated by each file are embedded in the object file itself. This means that no repositories are needed. See “What to Do If You Use Object Files From cfront's Repository” and “What to Do If You Use Multiple Repositories” for further information. | ||
| -pts | Splits instantiations into separate object files, with one function per object (including overloaded functions), and all class static data and virtual functions grouped into a single object. There is no equivalent CC -32 option. You can exercise fine-grained control over exactly which templates are instantiated in each file by using the instantiation pragmas described in “Pragmas for Template Instantiation”. | ||
| -ptv | Turns on verbose or verify mode, which displays each phase of instantiation as it occurs, together with the elapsed time in seconds that phase took to complete. You should use this option if you are new to templates. Verbose mode displays the reason an instantiation is done and the exact CC command used. The -ptv option is also supported by CC -32, and provides verbose information about the operation of the prelinker. The prelinker indicates which template instantiations are being assigned to which files, and which files are being recompiled. |
If you are used to the cfront template instantiation mechanism you may sometimes explicitly reference object files in the repository. This is often done when building an archive or a shared library. The general idea is to link a fake main program with a set of object files so as to populate the repository with the necessary template instantiations. The object files that were linked, along with the object files in the repository, are stored in an archive, or linked into a shared library.
cfront users do this to build an archive or library which has no unresolved template references. CC -32 users who wish to build archives and shared libraries where all template references have been resolved can do the following:
If you are building a shared library, the CC -32 driver will automatically run the prelinker on the set of object files being linked into the shared libraries. No further action is necessary on the part of the programmer.
If an archive is being built, the prelinker needs to be run explicitly on the object files, before invoking ar. See “Building Shared Libraries and Archives” for information on how to do this.
If you use the cfront template instantiation mechanism, you may sometimes use multiple repositories. For example, you may have an application which consists of multiple libraries. Each library is built in its own directory, and has its own repository. When you build the library, template functions are not instantiated. When the application is linked against these libraries, the necessary templates are instantiated at link time. The repositories provide enough information about where to find the necessary template declarations and implementations.
CC -32 does not use repositories, and you can use various strategies when linking a set of object files against a set of libraries that contain references to uninstantiated template functions. Some examples are given below:
If it is possible that all uninstantiated template functions can be instantiated in the object files being linked into the application, the prelinker will do so automatically. However, it is possible that a library uses a template internally, which is never used by the object files being linked into the application. Such templates are not instantiated by the prelinker, resulting in undefined symbols.
A better strategy is to prelink each library when it is built, so that the main program is not burdened with having to perform these instantiations. One problem occurs if multiple libraries use the same template functions: if each library is prelinked, multiple copies of such functions will be generated. Removal of duplicate functions takes place only in .o and .a files; shared libraries cannot have any duplicate code removed.
The language support for templates in the Silicon Graphics C++ environment is more extensive than for cfront. Some of the additional template language constructs supported by the Silicon Graphics C++ environment are listed below:
You may use nested classes, typedefs, and enums in class templates, including variant typedefs and enums. (A variant member type depends on the template parameters in some way.)
You may use floating point numbers, pointers to members, and more flexible specifications of constant addresses.
You may use default arguments for class template non-type parameters. For example:
template <int I = 1> class A {};
|
You may allow a non-type template parameter to have another template parameter as its type. For example:
template <class T, T t> class A {
public:
T a;
A(T init_val = t) { a = init_val; }
};
|
You may use what are essentially template classes instantiated with the template parameters of other class or function templates.
template <class T, int I> struct A {
static T b[I];
};
template <class T> void f(A<T,10> x) {}
template <class T> void f(A<T, 3> x) {}
void main()
{
A<int,10> m;
A<int,3> n;
int i = f(m);
int j = f(n);
}
|
The function template would be considered tagged twice by cfront, and the code calls tagged ambiguous by the Borland/C++ compiler.
You may use circular template references. For example:
template <class T> class B;
template <class T> class C;
template <class T> class A { B<T> *b; };
template <class T> class B { C<T> *c; };
template <class T> class C { A<T> *a; };
A<int> a;
|
cfront generates an error on this code.
CC is more consistent than other C++ compilers about where a class template name must be followed by template arguments. For example:
template <class T> struct X {
X();
~X();
X*x;
int X::* x2;
void f();
void g(){ X x;}
};
struct X<char> {
X();
~X(); // Borland error
X*x; // Borland error
int X::* x2; // Borland error
void f();
void g(){ X x;} // Borland error };
template <class T> void X<T>::f()
{
X x; // cfront error }
void X<char>::f()
{
X x; // cfront & Borland error
}
X<int> x;
X<char> xc;
|
cfront allows X to be used as a type name in the inline body of g but not in the out-of-line body of f. Borland/C++ uses one set of rules for class templates and a different set of rules for specializations. With CC, you may use X in all of the cases shown.
You may use forward declarations of class specializations.
You may use nested classes as type arguments of class templates.
You may use default arguments for all types of function templates, including arguments based on template parameter types. For example:
template <class T> void f(T t, int i = 1) {}
template <class T> void f(T t, T i = 1) {}
|