|
PSCF v1.4.0
|
Use Cases (Prev) Implicit vs. Explicit Templates (Next)
This section reviews some basic concepts and definitions involving C++ class templates, for reference. These comments focus primarily on class templates, rather than function templates.
A C++ class template definition provides a recipe for defining a class, rather than a concrete class definition. A template definition uses one or more template parameters. Template parameters that represent the name of a built-in or user-defined type are known as type parameter. Other non-type parameters may be used to represent a value of some specific type, such as an integer constant.
The syntax for defining a class template starts with the keyword "template" followed by a list of parameter declarations enclosed in angle brackets. As an example, consider the class template FArray in the Util namespace, which is a template for an array container of fixed size. This template takes a type parameter named Data that gives the type of each element and an integer parameter named Capacity that gives the number of elements. This template is defined using the syntax
where the ellipses indicate the omitted body of the class template definition. The symbols Data and Capacity are the template parameters.
Member functions of class templates may be defined outside the class definition, as for non-templated classes. The syntax for a class template member function definition begins with the "template" keyword followed by a list of parameter declarations, as for a class template definition, and is otherwise similar to a function definition for any other class member function.
As an example of a member function definition, consider the capacity() member function of the FArray class template. This function simply returns the value of the Capacity parameter. The complete definition is show below:
The "inline" qualifier used in this example encourages the compiler to inline this very small function, and does not appear in definitions of most longer functions.
A specialization of a class template is a class whose name is given by the name of a class template name followed by a valid list of template arguments in angle brackets. For exanple
is the name of a specialization of the template FArray with arguments Data = double and Capacity = 10. Each instance of the class FArray<double, 10> is an array of 10 double precision real numbers.
A complete class definition may be constructed by instantiating a class template with a specific list of template arguments. The actual type names and values assigned to template parameters in this process are referred to as template arguments. When a class template is instantiated with a specific list of arguments, the compiler generates object code for the resulting class for the memory layout of the class and for its member functions.
A class template specialization may be created either by instantiating the primary template or by defining an explicit specialization.
An instantiated class template specialization is a class template specialization that is created by instantiating the primary template definition.
An explicit specialization (also sometimes called a complete specialization) is a complete redefinition of a class template so as to apply to a specific list of template arguments. Explicit specialization is used when the primary template is does not yield the desired behavior for a specific list of arguments. The explicit specialization will be used as a replacement for the primary template for the specified list of arguments.
A partial specialization is a redefinition of a class template in which arguments are specified for a subset of the parameters of the primary template, while others are left as unspecified parameters. This generally results in a template with fewer unspecified parameters than the primary template. Like an explicit specialization, a partial specialization is a complete redefinition of the class and all of its member functions so as to apply to a particular set of possible template parameter lists.
An explicit instantiation definition is a type of C++ statement that instructs the compiler to instantiate a specific specialization of a template. The syntax for an explicit class template instantiation definition starts with the keywords "template class" followed by the name of the required template specialization. For example, the statement
is an explicit instantiation definition for the class template specialization FArray<double, 10>.
A class template may be instantiated by either explicit or implicit instantiation.
Explicit instantiation occurs when instantiation of a template specialization is triggered by an explicit instantiation definition.
Implicit instantiation instead occurs when a C++ compiler instantiates a class template as needed when it encounters the name of a specialization in a context that requires the construction or use of an instance of that class, and that is not part of an explicit instantiation definition. Implicit instantiation of a class template may be triggered by a declaration of a variable or function parameter that is an instance of a template specialization, or by instantiation of a class that is derived from a class template specialization.
By default, a C++ compiler will attempt implicit instantiation of a class template specialization the first time it is required to construct or use an instance of that specialization within a translation unit (i.e., within the file that is created by the C/C++ preprocessor by combining a source file with all of the other files that it directly or indirectly includes via preprocessor include directives). Only the first usage of a specific template specialization within such a translation unit triggers implicit instantiation. If the same specialization appears more than once in the same translation unit, the object code for that specialization may be re-used throughout the remainder of the enclosing translation unit.
Implicit instantiation of specific template specializations can be suppressed by an "explicit instantiation declaration". This is a language feature that was introduced in the 2011 version of the C++ language (C++11). The syntactical pattern for an explicit instantiation declaration starts with the keyword "extern" followed by the pattern for the corresponding explicit instantiation definition.
As an example, consider the class template Basis, which is defined in the Pscf::Prdc namespace. Like many templates used in PSCF, this is a template with a single integer parameter named D, which represents the dimension of space. The definition of this template thus looks something like this:
An explicit instantiation definition for a specialization of the Basis template with an argument D=3 would be given as
The corresponding explicit instantiation declaration for this specialization is instead
Note that the syntax for the explicit instantiation declaration is the same as that for the explicit instantiation definition, except for the addition of the keyword "extern" at the beginning of the declaration.
An explicit instantiation declaration is an instruction to the compiler that disables implicit instantation of the specified template specialization for the remainder of the relevant translation unit, and that instructs the linker to instead look for object code for that specialization during the linking process, after compilation. An explicit instantiation declaration thus instructs the compiler to treat a class that is created by instantiation of a class template the same way it would treat a non-template class, by separating compilation and linking. Such a declaration contains an implied promise to the compiler that a corresponding explicit instantiation definition must exist somewhere in a different file, and that the object code for the resulting template specialization will be made accessible during the linking process.
When a class template is instantiated, the compiler must have access to both the class definition (which contains declarations of all member variables and interfaces for all member functions) and the definitions of all class member functions. This requirement must be met for both explicit and implicit instantiation.
To guarantee that this requirement is always met, the usual advice given in textbooks and online discussions of C++ templates is that definitions of member functions for a class template should always be placed either:
These options are equivalent from the point of view of the compiler, since both guarantee that definitions for all member functions will be accessible in any file that includes the class header file. In older versions of C++, prior to C++11, this was sound advice, because this was indeed the only safe and practical way to organize files involving templates.
The introduction of explicit instantiation declarations to the language in C++11 has, however, made it practical for class member functions for some types of class templates to be placed in a separate file that is not included by the header file. This alternate pattern is used heavily in the PSCF source code, and discussed in detail on the next page.
Use Cases (Prev) C++ Templates (Up) Implicit vs. Explicit Templates (Next)