DIGITAL C++
Using DIGITAL C++ for DIGITAL UNIX Systems


Previous Contents Index

5.4.1 Instantiation Directives

DIGITAL C++ provides a mechanism for manual instantiation, using the #pragma define_template directive. This directive lets you tell the compiler what class or function template to instantiate in conjunction with the actual arguments with which the template is to be instantiated. The #pragma define_template directive has the following format:
#pragma define_template identifier <template_arguments>

Identifier is the name of the class or function template that the compiler is directed to instantiate at compile time. For the instantiation to succeed, the definition of the template must appear before the #pragma define_template directive.

Template_arguments is a list of one or more actual types that correspond to the template parameters for the particular class or function template being instantiated. Whatever type is specified is used as the type for the instantiation.

The following is an example of a valid template manual instantiation:


 
       //main.cxx 
       template <class T> void sort (T*); 
 
       int al[100]; 
       float a2[100]; 
 
       int main() 
       { 
           sort(a1); 
           sort(a2); 
           return 0; 
       } 
 
       //sort.cxx 
       template <class T> void sort (T *array) 
       { 
           /* body of sort */ 
       } 
 
       #pragma define_template sort<int> 
       #pragma define_template sort<float> 
 

To compile and link these sources, enter the following on the command line:


       cxx -nopt main.cxx sort.cxx 

Sorting an array of template class elements requires the use of additional pragmas for the module sort.cxx. For example:


 
       template <class T> void sort (T* array) 
       { 
           /*body of sort*/ 
       } 
 
       template <class T> class entity { 
       public: 
           T member; 
           int operator < (const entity<T> &) const; 
       } 
 
       template <class T> 
       int entity<T>::operator < (const entity<T> &operand) const 
       { 
            return member < operand.member; 
       } 
 
       int al[100]; 
       float a2[100]; 
       entity<int> a3[100]; 
 
       #pragma define_template sort<int> 
       #pragma define_template sort<float> 
       #pragma define_template sort<entity<int> > 
 
       void sort_all_arrays () 
       { 
           sort(a1); 
           sort(a2); 
           sort(a3); 
       } 
 

Note that the define_template pragma is position sensitive. If a define_template occurs lexically before a function, member function, or static data member template definition, the compiler is unable to instantiate the corresponding template because the body of that template is not present before the pragma directive.

The compiler instantiates all instances of sort and of entity::operator< needed for this compilation unit.

To organize a program to use the define_template pragma, you can place the declarations of class and functions templates into header files, and instantiate all instances of a particular template from a single compilation unit. The following example shows how to do this:


 
       // sort.h 
       template <class T> void sort (T*); 
 
       // entity.h 
       template <class T> class entity { 
       public: 
           T member; 
           int operator < (const entity<T> &) const; 
       }; 
 
       // main.cxx 
       #include "sort.h" 
       #include "entity.h" 
 
       int al[100]; 
       float a2[100]; 
       entity<int> a3[100]; 
 
       int main() 
       { 
           sort(a1); 
           sort(a2); 
           sort(a3); 
           return 0; 
       } 
 
       // sort.cxx 
       #include "sort.h" 
       #include "entity.h" 
       template <class T> void sort (T* array) 
       { 
           /*body of sort*/ 
       } 
       #pragma define_template sort<int> 
       #pragma define_template sort<float> 
       #pragma define_template sort<entity<int> > 
 

Compiling the following file provides a definition of entity::operator< with type int:


 
       // entity.cxx 
       #include "entity.h" 
 
       template <class T> 
       int entity<T>::operator < (const entity<T> &operand) const 
       { 
            return member < operand.member; 
       } 
 
       #pragma define_template entity<int> 
 

To compile this example, issue the following command:


       cxx main.cxx sort.cxx entity.cxx 

If the program uses other instantiations of entity in other compilation units, you can provide definitions of operator< for those entities by adding define_template pragmas to entity.cxx. For example, if other compilation units use the following instantiations of entity, appending the following pragmas to entity.cxx causes the compiler to generate instantiations of operator< for those requests of entity:


 
   entity<long> and entity< entity<int> >, 
   #pragma define_template entity<long> 
   #pragma define_template entity< entity<int> > 
 

Note that #pragma define_template is like any other pragma, so that it must appear on a single line. Pragmas may be continued on multiple lines by escaping the end of line with a backslash ( \ ) as with other preprocessor statements.

DIGITAL C++ also provides several other pragmas that provide finer control over the instantiation process. Instantiation pragmas can be used to control the instantiation of specific template entities or sets of template entities. There are two instantiation pragmas:

The argument to the instantiation pragma may be:
a template class name A<int>
a template class declaration class A<int>
a member function name A<int>::f
a static data member name A<int>::i
a static data declaration A<int>::i
a member function declaration void A<int>::f(int, char)
a template function declaration char* f(int, float)

A pragma in which the argument is a template class name (for example, A<int> or class A<int> is equivalent to repeating the pragma for each member function and static data member declared in the class. When instantiating an entire class, a given member function or static data member may be excluded using the do_not_instantiate pragma. For example:


 
 #pragma instantiate A<int> 
 #pragma do_not_instantiate A<int>::f 
 

The template definition of a template entity must be present in the compilation for an instantiation to occur. If an instantiation is explicitly requested by use of the instantiate pragma and no template definition is available or a specific definition is provided, an error is issued.


 
 template <class T> void f1(T);  // No body provided 
 template <class T> void g1(T);  // No body provided 
 void f1(int) {}  // Specific definition 
 void main() 
 { 
   int     i; 
   double  d; 
   f1(i); 
   f1(d); 
   g1(i); 
   g1(d); 
 } 
 #pragma instantiate void f1(int) // error - specific definition 
 #pragma instantiate void g1(int) // error - no body provided 
 

The functions 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, a linker error is produced).

A member function name (for example, A<int>::f can be used as a pragma argument 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 may 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:


 
 #pragma instantiate char* A<int>::f(int, char*) 
 

The argument to an instantiation pragma must not be a compiler-generated function, an inline function, or a pure virtual function.

Alternatively, you could use the -define_templates command-line option to instantiate templates. Using the -define_templates option requires the same template definition and compilation procedures as previously described for the define_template pragma.

Considering the previous examples in this section, you can use this qualifier to supply definitions of sort<int>, sort<float>, and sort<entity><int> by compiling the following file using -define_templates:


 
       // sort.cxx 
       #include "sort.h" 
       #include "entity.h" 
 
       template <class T> 
       static sort (T* array) 
       { 
           /*body of sort*/ 
       } 
 
 
       static void function_never_used () 
       { 
           int al[100]; 
           float a2[100]; 
           entity<int> a3[100]; 
 
           sort(a1); 
           sort(a2); 
           sort(a3); 
       } 
 

There are also two other command-line options that allow for manual template instantiation. They are the -tused and -tlocal options. The -tused option acts like -define_templates, except that only those template instantiations that are referenced in the source file are actually instantiated. The -tlocal option acts like -tused, except that the templates are instantiated with internal linkage. This provides a simple way to build applications but creates executables that are larger than necessary. It also fails if the template classes being instantiated have static data members.

5.5 Advanced Program Development and Templates

The following sections discuss templates in the context of advanced program development.

5.5.1 Dependency Management

DIGITAL C++ does no dependency management of its own. Because template instantiations are compiled when source files that reference those instantiations are compiled, those source files must be recompiled if the template declaration or definition changes. The -M output from the compiler lists the implicitly included files, so that the make program can automatically recompile any source files that depend upon template files. If make is not being used, it is the user's responsibility to ensure that instantiations that have changed are recompiled. The user does so by recompiling at least one source file that references the changed instantiations.

Note that when instantiations are included in libraries, or when multiple repositories are used, there is a possibility that stale instantiations may be present. For example, if a template class is used in a source file, and that template class is modified, the source file is recompiled and the instantiations that appear in the writable repository are updated. However, if instances with the same name appear in objects or libraries that are being linked into the application, those older instantiations are used in preference to the instantiations in the repositories.

Also, if a member function of the class that is not referenced in the recompiled source is referenced from a file that is not recompiled with the new class definition, some instantiations in the application that use member functions based on the newer class definition are mixed with stale instantiations that are based on the older class definition. It is important to know who is using a template before placing it into a library or read-only repository, and before modifying it, so that all affected instances can be kept compatible.

5.5.2 Mixing Automatic and Manual Instantiation

Object files that have been compiled using manual instantiation can be linked freely with objects that have been compiled using automatic instantiation. To ensure that the template instantiations needed by the files compiled with automatic instantiation are provided, the application must be linked using automatic instantiation, and the appropriate repositories must be present. When a template instantiation is present in an explicitly named object file or object library it takes precedence over the same named instantiation in a repository.

5.5.3 Creating Libraries

Creating libraries with object files created with automatic instantiations is relatively straightforward. You must decide where the instantiations that were generated automatically are provided to the users of the library. For applications that use the library to link successfully, all template instantiations that are needed by the code in the library must be available at link time. Because template instantiation happens at compile time, the object files that contain the instantiated templates must be available at link time. This can be done in two ways:

If possible, it is easiest to put the instantiations in the library. Note that the instantiations in the library hide the same named instantiations in any repositories or any libraries following the library on the command line. This is a good choice if the instantiations are internal to the library and are not instantiated directly by the user's code. It is also a good choice if the templates that are instantiated are stable, and will not be modified by the user. To put the instantiations in the library, add all of the object files in the repositories required by the library into the library. For example, if a library is being made from the source files a.cxx, b.cxx, and c.cxx, the following code places into the library all the instantiations necessary along with the specified object files:


 cxx -c -ptr lib_repository a.cxx b.cxx c.cxx 
 ar r mylib.a a.o b.o c.o lib_repository/*.o 

If the template instantiations can be overridden by the user, the templates should be provided in a repository that the user specifies after all the user's repositories. For the previous example, create the library as follows:


 cxx -c -ptr lib_repository a.cxx b.cxx c.cxx 
 ar r mylib.a a.o b.o c.o 

When linking the application, the user would specify lib_repository as the last read-only repository on the line as follows:


 cxx -c -ptr ./cxx_repository -ptr lib_repository user_code.cxx mylib.a 

The user must explicitly name the repository when linking, even if it is the default repository ./cxx_repository; cxx first satisfies all unresolved instantiations from ./cxx_repository, and uses lib_repository to resolve any remaining unresolved instantiations.

Note that only the instantiations that are required by the code in the library are generated in the library repository lib_repository. If you must provide other instantiations that the user requires but cannot instantiate, you must provide these instantiations using manual template instantiation.

If multiple libraries are used and contain the same named instantiations, the actual instantiation used is the one from the first library that can satisfy the request.

5.5.4 Multiple Repositories

As shown in the previous example, multiple repositories can be specified to link an application. The first repository named is the read-write repository, and when compiling, DIGITAL C++ writes instantiation object files into it. At link time, all repositories are read only.

The repositories are searched in a linear order, iteratively, and satisfy only the unresolved instantiations from each pass. That is, references from instantiations that are added in one pass are not resolved until the next pass. Consider the link line in the previous example:


   cxx -c -ptr ./cxx_repository -ptr lib_repository user_code.cxx mylib.a 

In this example, all references that could be resolved from lib_repository would be resolved. Any reference arising from an instantiation in lib_repository would be resolved by instantiations in ./cxx_repository.

5.6 Command-Line Options for Template Instantiation

The following cxx command-line options are specific to the instantiation of templates:

-define_templates
-tall

Instantiate all template entities declared or referenced in the compilation unit. For each fully instantiated template class, all its member functions and static data members are instantiated even if they were not used. Nonmember template functions are instantiated even if the only reference was a declaration. Instantiations are created with external linkage. Overrides -pt at compile time. Instantiations are placed in the user's .o file.

-Hf

Stops the cxx command after the prelinker runs, and before the final link. Provided for compatibility with previous versions of DIGITAL C++. This option is not useful with the Version 6.0 compiler.

-[no]implicit_include

Enable or disable inclusion of source files as a method of finding definitions of template entities. Implicit inclusion is enabled by default, and it and disabled when compiling with -E or -P . The search rules for finding template definition files are the same as for include files.

You might want to disable implicit inclusion with the -ms and -std ms options to match the behavior on Microsoft C++ more closely.

-nopt

Directs the compiler not to instantiate templates automatically.

-nopragma_template

Directs the compiler to ignore any #pragma define_template directives. This option is provided for users who want to migrate quickly to automatic instantiation without having to remove all the pragma directives from their code base.

-pt

Directs the compiler to instantiate templates automatically. This option is the default. Instantiations are placed in the repository.

-ptr pathname

Specifies a repository, with ./cxx_repository as the default. If you specify several repositories, only the first is writable, and the rest are read only. Read-only repositories are used only at link time.

Specifying this option at link time enables DIGITAL C++ to recognize and use the template instantiation information files within the specified repository. If you use this option, make sure that the repository specified at compile time is the same one specified at link time.

-ptsuf "list"

Specifies a list of file name suffixes that are valid for template definition files. Items in the list must be separated by commas and each suffix preceded by a period. A suffix may have no more than eight characters excluding the beginning period. The default is ".cxx,.CXX,.C,.cc,.CC,.cpp,.c".

-ptv

Turns on verbose or verify mode to display each phase of instantiation as it occurs. This option is useful as a debugging aid.

-tlocal

Similar to -tused except that the functions are given internal linkage. This option provides a simple mechanism for getting started with templates. The compiler instantiates as local functions the functions used in each compilation unit, and the program links and runs correctly (barring problems resulting from multiple copies of local static variables). However, because many copies of the instantiated functions can be generated, this option might not be not suitable for production use.

Note that -tlocal cannot be used in conjunction with automatic template instantiation. If automatic instantiation is enabled by default, it is disabled by the -tlocal option. Explicit use of -tlocal and -pt is an error.

-tused

Instantiate those template entities that were used in the compilation. This includes all static data members for which there are template definitions. Overrides -pt at compile time.

-ttimestamp

Used with automatic instantiation. Causes automatic instantiation to instantiate templates only if they are already in the repository, or if the existing instantiations in the repository are older than the timestamp in the repository.


Previous Next Contents Index