Ru-Brd |
There are three kinds of template parameters:
Template parameters are declared in the introductory parameterization clause of a template declaration. Such declarations do not necessarily need to be named: template <typename, int> class X; A parameter name is, of course, required if the parameter is referred to later in the template. Note also that a template parameter name can be referred to in a subsequent parameter declaration (but not before): template <typename T, // the first parameter is used in the T* Root, // declaration of the second one and template<T*> class Buf> // the third one class Structure; 8.2.1 Type ParametersType parameters are introduced with either the keyword typename or the keyword class : The two are entirely equivalent. [2] The keyword must be followed by a simple identifier and that identifier must be followed by a comma to denote the start of the next parameter declaration, a closing angle bracket ( > ) to denote the end of the parameterization clause, or an equal sign ( = ) to denote the beginning of a default template argument.
Within a template declaration, a type parameter acts much like a typedef name . For example, it is not possible to use an elaborated name of the form class T when T is a template parameter, even if T were to be substituted by a class type: template <typename Allocator> class List { class Allocator* allocator; // ERROR friend class Allocator; // ERROR }; It is possible that a mechanism to enable such a friend declaration will be added in the future. 8.2.2 Nontype ParametersNontype template parameters stand for constant values that can be determined at compile or link time. [3] The type of such a parameter (in other words, the type of the value for which it stands) must be one of the following:
All other types are currently excluded (although floating-point types may be added in the future, see Section 13.4 on page 210). Perhaps surprisingly, the declaration of a nontype template parameter can in some cases also start with the keyword typename : template<typename T, // a type parameter typename T::Allocator* Allocator> // a nontype parameter class List; The two cases are easily distinguished because the first is followed by a simple identifier, whereas the second is followed by a qualified name (in other words, a name containing a double colon , :: ). Section 1.1 on page 43 and Section 9.3.2 on page 130 explain the need for the keyword typename in the nontype parameter. Function and array types can be specified, but they are implicitly adjusted to the pointer type to which they decay: template<int buf[5]> class Lexer; // buf is really an int* template<int* buf> class Lexer; // OK: this is a redeclaration Nontype template parameters are declared much like variables , but they cannot have nontype specifiers like static , mutable , and so forth. They can have const and volatile qualifiers, but if such a qualifier appears at the outermost level of the parameter type, it is simply ignored: template<int const length> class Buffer; // const is useless here template<int length> class Buffer; // same as previous declaration Finally, nontype parameters are always rvalues : Their address cannot be taken, and they cannot be assigned to. 8.2.3 Template Template ParametersTemplate template parameters are placeholders for class templates. They are declared much like class templates, but the keywords struct and union cannot be used: template <template<typename X> class C> // OK void f(C<int>* p); template <template<typename X> struct C> // ERROR: struct not valid here void f(C<int>* p); template <template<typename X> union C> // ERROR: union not valid here void f(C<int>* p); In the scope of their declaration, template template parameters are used just like other class templates. The parameters of template template parameters can have default template arguments. These default arguments apply when the corresponding parameters are not specified in uses of the template template parameter: template <template<typename T, typename A = MyAllocator> class Container> class Adaptation { Container<int> storage; // implicitly equivalent to // Container<T, MyAllocator> }; The name of a template parameter of a template template parameter can be used only in the declaration of other parameters of that template template parameter. The following contrived template illustrates this concept: template <template<typename T, T*> class Buf> class Lexer { static char storage[5]; Buf<char, &Lexer<Buf>::storage> buf; }; template <template<typename T> class List> class Node { static T* storage; // ERROR: a parameter of a template template // parameter cannot be used here }; Usually however, the names of the template parameters of a template template parameter are not used. As a result, the former parameters are often left unnamed altogether. For example, our earlier Adaptation template could be declared as follows : template <template <typename, typename = MyAllocator> class Container> class Adaptation { Container<int> storage; // implicitly equivalent to // Container<int, MyAllocator> }; 8.2.4 Default Template ArgumentsCurrently, only class template declarations can have default template arguments (see Section 13.3 on page 207 for likely changes in this area). Any kind of template parameter can be equipped with a default argument, although it must match the corresponding parameter. Clearly, a default argument should not depend on its own parameter. However, it may depend on previous parameters: template <typename T, typename Allocator = allocator<T> > class List; Similar to default function call arguments, a template parameter can have a default template argument only if default arguments were also supplied for the subsequent parameters. The subsequent default values are usually provided in the same template declaration, but they could also have been declared in a previous declaration of that template. The following example makes this clear: template <typename T1, typename T2, typename T3, typename T4 = char, typename T5 = char> class Quintuple; // OK template <typename T1, typename T2, typename T3 = char, typename T4, typename T5> class Quintuple; // OK: T4 and T5 already have defaults template <typename T1 = char, typename T2, typename T3, typename T4, typename T5> class Quintuple; // ERROR: T1 cannot have a default argument // because T2 doesn't have a default Default template arguments cannot be repeated: template<typename T = void> class Value; template<typename T = void> class Value; // ERROR: repeated default argument |
Ru-Brd |