C++ User's Guide HomeContentsPreviousNextIndex


Chapter 4

Compiling Templates

Template compilation requires the C++ compiler to do more than traditional UNIX compilers have done. The C++ compiler must generate object code for template instances on an as-needed basis. It might share template instances among separate compilations using a template repository. It might accept some template compilation options. It must locate template definitions in separate source files and maintain consistency between template instances and mainline code.

4.1 Verbose Compilation

When given the flag --verbose=template, the C++ compiler notifies you of significant events during template compilation. Conversely, the compiler does not notify you when given the default, --verbose=no%template. The +w option might give other indications of potential problems when template instantiation occurs.

4.2 Template Commands

The CCadmin(1) command administers the template repository. For example, changes in your program can render some instantiations superfluous, thus wasting storage space. The CCadmin -clean command (formerly ptclean) clears out all instantiations and associated data. Instantiations are recreated only when needed.

4.3 Template Instance Placement and Linkage

You can instruct the compiler to use one of five instance placement and linkage methods: external, static, global, explicit, and semi-explicit.

You should use the external instances method, which is the default, unless there is a very good reason to do otherwise. See the C++ Programming Guide for further information.

4.3.1 External Instances

With the external instances method, all instances are placed within the template repository. The compiler ensures that exactly one consistent template instance exists; instances are neither undefined nor multiply defined. Templates are reinstantiated only when necessary.

Template instances receive global linkage in the repository. Instances are referenced from the current compilation unit with external linkage.

Specify external linkage with the --instances=extern option (the default option).

Because instances are stored within the template repository, you must use the CC command to link C++ objects that use external instances into programs.

If you wish to create a library that contains all template instances that it uses, use the CC command with the --xar option. Do not use the ar command. For example:

example% CC -xar -o libmain.a a.o b.o c.o

See Chapter 6 for more information.

4.3.2 Static Instances

With the static instances method, all instances are placed within the current compilation unit. As a consequence, templates are reinstantiated during each recompilation; instances are not saved to the template repository.

Instances receive static linkage. These instances will not be visible or usable outside the current compilation unit. As a result, templates might have identical instantiations in several object files. This has the following undesirable consequences:

Compilation is potentially faster with static instances, so this method might also be suitable during Fix-and-Continue debugging. (See Debugging a Program With dbx.)

Specify static instance linkage with the --instances=static compiler option.

4.3.3 Global Instances

With the global instances method, all instances are placed within the current compilation unit. As a consequence, templates are reinstantiated during each recompilation; they are not saved to the template repository.

Template instances receive global linkage. These instances are visible and usable outside the current compilation unit. As a consequence, instantiation in more than one compilation unit results in multiple symbol definition errors during linking. The global instances method is therefore suitable only when you know that instances will not be repeated.

Specify global instances with the --instances=global option.

4.3.4 Explicit Instances

In the explicit instances method, instances are generated only for templates that are explicitly instantiated. Implicit instantiations are not satisfied. Instances are placed within the current compilation unit. As a consequence, templates are reinstantiated during each recompilation; they are not saved to the template repository.

Template instances receive global linkage. These instances are visible and usable outside the current compilation unit. Multiple explicit instantiations within a program result in multiple symbol definition errors during linking. The explicit instances method is therefore suitable only when you know that instances are not repeated, such as when you construct libraries with explicit instantiation.

Specify explicit instances with the --instances=explicit option.

4.3.5 Semi-Explicit Instances

When you use the semi-explicit instances method, instances are generated only for templates that are explicitly instantiated or implicitly instantiated within the body of a template. Implicit instantiations in the mainline code are not satisfied. Instances are placed within the current compilation unit. As a consequence, templates are reinstantiated during each recompilation; they are not saved to the template repository.

Explicit instances receive global linkage. These instances are visible and usable outside the current compilation unit. Multiple explicit instantiations within a program result in multiple symbol definition errors during linking.The semi-explicit instances method is therefore suitable only when you know that explicit instances will not be repeated, such as when you construct libraries with explicit instantiation.

Implicit instances used from within the bodies of explicit instances receive static linkage. These instances are not visible outside the current compilation unit. As a result, templates can have identical instantiations in several object files. This has two undesirable consequences:

Specify semi-explicit instances with the --instances=semiexplicit option.

4.4 The Template Repository

The template repository stores template instances between separate compilations so that template instances are compiled only when necessary. The template repository contains all nonsource files needed for template instantiation when using the external instances method. The repository is not used for other kinds of instances.

4.4.1 Repository Structure

The template repository is contained, by default, within the Sun WorkShop cache directory (SunWS_cache). The Sun WorkShop cache directory is contained within the directory in which the output files will be placed. You can change the name of the cache directory by setting the SUNWS_CACHE_NAME environment variable.

4.4.2 Writing to the Template Repository

When the compiler must store template instances, it stores them within the template repository corresponding to the output file. That is,

example% CC -o sub/a.o a.cc

this command line:

writes the object file to ./sub/a.o and writes template instances into the repository contained within ./sub/SunWS_cache. If the cache directory does not exist, and the compiler needs to instantiate a template, the directory is created for you.

4.4.3 Reading From Multiple Template Repositories

The compiler reads from the template repositories corresponding to the object files that it reads. That is,

example% CC sub1/a.o sub2/b.o

this command line:

reads from ./sub1/SunWS_cache and ./sub2/SunWS_cache, and, if necessary, writes to ./SunWS_cache.

4.4.4 Sharing Template Repositories

Templates that are within a repository must not violate the one-definition rule of the ISO/ANSI C++ standard. That is, a template must have the same source in all uses of the template. Violating this rule produces undefined behavior. The simplest, though most conservative, way to ensure the rule is not violated is to build only one program or library within any one directory.

4.5 Template Definition Searching

When you use the definitions-separate template organization, template definitions are not available in the current compilation unit, and the compiler must search for the definition. This section describes how the compiler locates the definition.

Definition searching is somewhat complex and prone to error. Therefore, you should use the definitions-included template file organization if possible. Doing so helps you avoid definition searching altogether. See the C++ Programming Guide.


Note – If you use the -template=no%extdef option, the compiler will not search for separate source files.

4.5.1 Source File Location Conventions

Without the specific directions provided with an options file, the compiler uses a Cfront-style method to locate template definition files. This method requires that the template definition file contain the same base name as the template declaration file. This method also requires that the template definition file be on the current include path. For example, if the template function foo() is located in foo.h, the matching template definition file should be named foo.cc or some other recognizable source-file extension (.C, .c, .cc, .cpp, or .cxx). The template definition file must be located in one of the normal include directories or in the same directory as its matching header file.

4.5.2 Definitions Search Path

As an alternative to the normal search path set with -I, you can specify a search directory for template definition files with the option -ptidirectory. Multiple -pti flags define multiple search directories--that is, a search path. If you use -ptidirectory, the compiler looks for template definition files on this path and ignores the -I flag. Since the -ptidirectory flag complicates the search rules for source files, use the -I option instead of the -ptidirectory option.

4.6 Template Instance Automatic Consistency

The template repository manager ensures that the states of the instances in the repository are consistent and up-to-date with your source files.

For example, if your source files are compiled with the -g option (debugging on), the files you need from the database are also compiled with -g.

In addition, the template repository tracks changes in your compilation. For example, if you have the --DDEBUG flag set to define the name DEBUG, the database tracks this. If you omit this flag on a subsequent compile, the compiler reinstantiates those templates on which this dependency is set.

4.7 Compile-Time Instantiation

Instantiation is the process by which a C++ compiler creates a usable function or object from a template. The Sun WorkShop 6 C++ compiler uses compile-time instantiation, which forces instantiations to occur when the reference to the template is being compiled.

The advantages of compile-time instantiation are:

Templates can be instantiated multiple times if source files reside in different directories or if you use libraries with template symbols.

4.8 Template Options File

The template options file is a user-provided optional file that contains the options needed to locate template definitions and to control instance recompilation. In addition, the options file provides features for controlling template specialization and explicit instantiation. However, because the C++ compiler now supports the syntax required to declare specializations and explicit instantiation in the source code, you should not use these features.


Note – The template options file may not be supported in future releases of the C++ compiler.

The options file is named CC_tmpl_opt and resides within the SunWS_config directory. This directory name may be changed using the SUNWS_CONFIG_NAME environment variable.

The options file is an ASCII text file containing a number of entries. An entry consists of a keyword followed by expected text and terminated with a semicolon (;). Entries can span multiple lines, although the keywords cannot be split.

4.8.1 Comments

Comments start with a # character and extend to the end of the line. Text within a comment is ignored.

# Comment text is ignored until the end of the line.

4.8.2 Includes

You may share options files among several template databases by including the options files. This facility is particularly useful when building libraries containing templates. During processing, the specified options file is textually included in the current options file. You can have more than one include statement and place them anywhere in the options file. The options files can also be nested.

include "options-file";

4.8.3 Source File Extensions

You can specify different source file extensions for the compiler to search for when the compiler is using its default Cfront-style source-file-locator mechanism. The format is:

extensions "ext-list";

The ext-list is a list of extensions for valid source files in a space-separated format such as:

extensions ".CC .c .cc .cpp";

In the absence of this entry from the options file, the valid extensions for which the compiler searches are .cc, .c, .cpp, .C, and .cxx.

4.8.4 Definition Source Locations

You can explicitly specify the locations of definition source files using the definition option file entry. Use the definition entry when the template declaration and definition file names do not follow the standard Cfront-style conventions. The entry syntax is:

definition name in "file-1",[ "file-2" ..., "file-n"] [nocheck "options"];

The name field indicates the template for which the option entry is valid. Only one definition entry per name is allowed. That name must be a simple name; qualified names are not allowed. Parentheses, return types, and parameter lists are not allowed. Regardless of the return type or parameters, only the name itself counts. As a consequence, a definition entry may apply to several (possibly overloaded) templates.

The "file-n" list field specifies the files that contain the template definitions. The search for the files uses the definition search path. The file names must be enclosed in quotes (" "). Multiple files are available because the simple template name may refer to different templates defined in different files, or because a single template may have definitions in multiple files. For example, if func is defined in three files, then those three files must be listed in the definition entry.

The nocheck field is described at the end of this section.

In the following example, the compiler locates the template function foo in foo.cc, and instantiates it. In this case, the definition entry is redundant with the default search.

CODE EXAMPLE 4-1   Redundant Definition Entry
foo.cc
template <class T> T foo( T t ) { }
CC_tmpl_opt
definition foo in "foo.cc";


The following example shows the definition of static data members and the use of simple names.

CODE EXAMPLE 4-2   Definition of Static Data Members and Use of Simple Names
foo.h
template <class T> class foo { static T* fooref; };
foo_statics.cc
#include "foo.h"
template <class T> T* foo<T>::fooref = 0
CC_tmpl_opt
definition fooref in "foo_statics.cc";


The name provided for the definition of fooref is a simple name and not a qualified name (such as foo::fooref). The reason for the definition entry is that the file name is not foo.cc (or some other recognizable extension) and cannot be located using the default Cfront-style search rules.

The following example shows the definition of a template member function. As the example shows, member functions are handled exactly like static member initializers.

CODE EXAMPLE 4-3   Template Member Function Definition
foo.h
template <class T> class foo { T* foofunc(T); };
foo_funcs.cc
#include "foo.h"
template <class T> T* foo<T>::foofunc(T t) {}
CC_tmpl_opt
definition foofunc in "foo_funcs.cc";


The following example shows the definition of template functions in two different source files.

CODE EXAMPLE 4-4   Definition of Template Functions in Different Source Files
foo.h
template <class T> class foo {
    T* func( T t );
    T* func( T t, T x );
};
foo1.cc
#include "foo.h"
template <class T> T* foo<T>::func( T t ) { }
foo2.cc
#include "foo.h"
template <class T> T* foo<T>::func( T t, T x ) { }
CC_tmpl_opt
definition func in "foo1.cc", "foo2.cc";


In this example, the compiler must be able to find both of the definitions of the overloaded function func(). The definition entry tells the compiler where to find the appropriate function definitions.

Sometimes recompiling is unnecessary when certain compilation flags change. You can avoid unnecessary recompilation using the nocheck field of the definition option file entry, which tells the compiler and template database manager to ignore certain options when checking dependencies. If you do not want the compiler to reinstantiate a template function because of the addition or deletion of a specific command-line flag, use the nocheck flag. The entry syntax is:

definition name in "file-1"[, "file-2" ..., "file-n"] [nocheck "options"];

The options must be enclosed in quotes (" ").

In the following example, the compiler locates the template function foo in foo.cc, and instantiates it. If a reinstantiation check is later required, the compiler will ignore the -g option.

CODE EXAMPLE 4-5   nocheck Option
foo.cc
template <class T> T foo( T t ) {}
CC_tmpl_opt
definition foo in "foo.cc" nocheck "-g";


4.8.5 Template Specialization Entries

Until recently, the C++ language provided no mechanism for specializing templates, so each compiler provided its own mechanism. This section describes the specialization of templates using the mechanism of previous versions of the C++ compilers. This mechanism is only supported in compatibility mode (-compat[=4]).

The special entry tells the compiler that a given function is a specialization and should not be instantiated when the compiler encounters the function. When using the compile-time instantiation method, use special entries in the options file to preregister the specializations. The syntax is:

special declaration;

The declaration is a legal C++-style declaration without return types. For example:

CODE EXAMPLE 4-6   special Entry
foo.h
template <class T> T foo( T t ) { };
main.cc
#include "foo.h"
CC_tmpl_opt
special foo(int);


The preceding options file informs the compiler that the template function foo() should not be instantiated for the type int, and that a specialized version is provided by the user. Without that entry in the options file, the function may be instantiated unnecessarily, resulting in errors:

CODE EXAMPLE 4-7   Example of When special Entry Should be Used
foo.h
template <classT> T foo( T t ) { return t + t; }
file.cc
#include "foo.h"
int func( ) { return foo( 10 ); }
main.cc
#include "foo.h"
int foo( int i ) { return i * i; } // the specialization
int main( ) { int x = foo( 10 ); int y = func(); 
return 0; }


In the preceding example, when the compiler compiles main.cc, the specialized version of foo is correctly used because the compiler has seen its definition. When file.cc is compiled, however, the compiler instantiates its own version of foo because it doesn't know foo exists in main.cc. In most cases, this process results in a multiply-defined symbol during the link, but in some cases (especially libraries), the wrong function may be used, resulting in runtime errors. If you use specialized versions of a function, you should register those specializations.

The special entries can be overloaded, as in this example:

CODE EXAMPLE 4-8   Overloading special Entries
foo.h
template <classT> T foo( T t ) {}
main.cc
#include "foo.h"
int   foo( int   i ) {}
char* foo( char* p ) {}
CC_tmpl_opt
special foo(int);
special foo(char*);


To specialize a template class, include the template arguments in the special entry:

CODE EXAMPLE 4-9   Specializing a Template Class
foo.h
template <class T> class Foo { ... various members ... };
main.cc
#include "foo.h"
int main( ) { Foo<int> bar; return 0; }
CC_tmpl_opt
special class Foo<int>;


If a template class member is a static member, you must include the keyword static in your specialization entry:

CODE EXAMPLE 4-10   Specializing a Static Template Class Member
foo.h
template <class T> class Foo { public: static T func(T); 
};
main.cc
#include "foo.h"
int main( ) { Foo<int> bar; return 0; }
CC_tmpl_opt
special static Foo<int>::func(int);



Sun Microsystems, Inc.
Copyright information. All rights reserved.
Feedback
Library   |   Contents   |   Previous   |   Next   |   Index