Ru-Brd |
Template arguments are the "values" that are substituted for template parameters when instantiating a template. These values can be determined using several different mechanisms:
8.3.1 Function Template ArgumentsTemplate arguments for a function template can be specified explicitly or deduced from the way the template is used. For example: // details/max.cpp template <typename T> inline T const& max (T const& a, T const& b) { return a<b?b:a; } int main() { max<double>(1.0, -3.0); // explicitly specify template argument max(1.0, -3.0); // template argument is implicitly deduced // to be double max<int>(1.0, 3.0); // the explicit <int> inhibits the deduction; // hence the result has type int } Some template arguments can never be deduced (see Chapter 11). The corresponding parameters are best placed at the beginning of the list of template parameters so they can be specified explicitly while allowing the other arguments to be deduced. For example: // details/implicit.cpp template <typename DstT, typename SrcT> inline DstT implicit_cast (SrcT const& x) // SrcT can be deduced, { // but DstT cannot return x; } int main() { double value = implicit_cast<double>(-1); } If we had reversed the order of the template parameters in this example (in other words, if we had written template<typename SrcT, typename DstT> ), a call of implicit_cast would have to specify both template arguments explicitly. Because function templates can be overloaded, explicitly providing all the arguments for a function template may not be sufficient to identify a single function: In some cases, it identifies a set of functions. The following example illustrates a consequence of this observation: template <typename Func, typename T> void apply (Func func_ptr, T x) { func_ptr(x); } template <typename T> void single(T); template <typename T> void multi(T); template <typename T> void multi(T*); int main() { apply(&single<int>, 3); // OK apply(&multi<int>, 7); // ERROR: no single multi<int> } In this example, the first call to apply() works because the type of the expression &single<int> is unambiguous. As a result, the template argument value for the Func parameter is easily deduced. In the second call, however, &multi<int> could be one of two different types and therefore Func cannot be deduced in this case. Furthermore, it is possible that explicitly specifying the template arguments for a function template results in an attempt to construct an invalid C++ type. Consider the following overloaded function template ( RT1 and RT2 are unspecified types): template<typename T> RT1 test(typename T::X const*); template<typename T> RT2 test(...); The expression test<int> makes no sense for the first of the two function templates because type int has no member type X . However, the second template has no such problem. Therefore, the expression &test<int> identifies the address of a single function. The fact that the substitution of int into the first template fails does not make the expression invalid. This "substitution-failure-is-not-an-error" (SFINAE) principle is clearly an important ingredient to make the overloading of function templates practical. However, it also enables remarkable compile-time techniques. For example, assuming that types RT1 and RT2 are defined as follows : typedef char RT1; typedef struct { char a[2]; } RT2; We can check at compile time (in other words, as a so-called constant-expression ) whether a given type T has a member type X : #define type_has_member_type_X(T) \ (sizeof(test<T>(0)) == 1) To understand the expression in this macro, it is convenient to analyze from the outside to the inside. First, the sizeof expression will equal one if the first test template (which returns a char of size one) is selected. The other template returns a structure with a size that is at least two (because it contains an array of size two). In other words, this is a device to determine as a constant-expression whether the first or second template was selected for the call test<T>(0) . Clearly, the first template cannot be selected if the given type T has no member type X . However, if the given type has a member type X , then the first template is preferred because overload resolution (see Appendix B) prefers the conversion from zero to a null pointer constant over binding an argument to an ellipsis parameter (ellipsis parameters are the weakest kind of binding from an overload resolution perspective). Similar techniques are explored in Chapter 15. The SFINAE principle protects only against attempts to create invalid types but not against attempts to evaluate invalid expressions. The following example is therefore invalid C++: template<int I> void f(int (&)[24/(4-I)]); template<int I> void f(int (&)[24/(4+I)]); int main() { &f<4>; // ERROR: division by zero (SFINAE doesn't apply) } This example is an error even though the second template supports the substitution without leading to a division by zero. This sort of error must occur in the expression itself and not in binding of an expression to a template parameter. Indeed, the following example is valid: template<int N> int g() { return N; } template<int* P> int g() { return *P } int main() { return g<1>(); // 1 cannot be bound to int* parameter, } // but SFINAE principle applies See Section 15.2.2 on page 266 and Section 19.3 on page 353 for further applications of the SFINAE principle. 8.3.2 Type ArgumentsTemplate type arguments are the "values" specified for template type parameters. Most commonly used types can be used as template arguments, but there are two exceptions:
An example illustrates these two exceptions: template <typename T> class List { }; typedef struct { double x, y, z; } Point; typedef enum { red, green, blue } *ColorPtr; int main() { struct Association { int* p; int* q; }; List<Assocation*> error1; // ERROR: local type in template argument List<ColorPtr> error2; // ERROR: unnamed type in template // argument List<Point> ok; // OK: unnamed class type named through // a typedef } Although other types can, in general, be used as template arguments, their substitution for the template parameters must lead to valid constructs: template <typename T> void clear (T p) { *p = 0; // requires that the unary * be applicable to T } int main() { int a; clear(a); // ERROR: int doesn't support the unary * } 8.3.3 Nontype ArgumentsNontype template arguments are the values substituted for nontype parameters. Such a value must be one of the following things:
When matching an argument to a parameter that is a pointer or reference, user -defined conversions (constructors for one argument and conversion operators) and derived-to-base conversions are not considered , even though in other circumstances they would be valid implicit conversions. Implicit conversions that make an argument more const or more volatile are fine. Here are some valid examples of nontype template arguments: template <typename T, T nontype_param> class C; C<int, 33>* c1; // integer type int a; C<int*, &a>* c2; // address of an external variable void f(); void f(int); C<void (*)(int), &f>* c3; // name of a function: overload resolution selects // f(int) in this case; the & is implied class X { int n; static bool b; }; C<bool&, X::b>* c4; // static class members are acceptable variable // and function names C<int X::*, &X::n>* c5; // an example of a pointer-to-member constant template<typename T> void templ_func(); C<void (), &templ_func<double> >* c6; // function template instantiations are functions too A general constraint of template arguments is that a compiler or a linker must be able to express their value when the program is being built. Values that aren't known until a program is run (for example, the address of local variables) aren't compatible with the notion that templates are instantiated when the program is built. Even so, there are some constant values that are, perhaps surprisingly, not currently valid:
One of the problems with string literals is that two identical literals can be stored at two distinct addresses. An alternative (but cumbersome) way to express templates instantiated over constant strings involves introducing an additional variable to hold the string: template <char const* str> class Message; extern char const hello[] = "Hello World!"; Message<hello>* hello_msg; Note the need for the extern keyword because otherwise a const array variable would have internal linkage. See Section 4.3 on page 40 for another example and Section 13.4 on page 209 for a discussion of possible future changes in this area. Here are few other (less surprising) invalid examples: template<typename T, T nontype_param> class C; class Base { int i; } base; class Derived : public Base { } derived_obj; C<Base*, &derived_obj>* err1; // ERROR: derived-to-base conversions are // not considered C<int&, base.i>* err2; // ERROR: fields of variables aren't // considered to be variables int a[10]; C<int*, &a[0]>* err3; // ERROR: addresses of individual array // elements aren't acceptable either 8.3.4 Template Template ArgumentsA template template argument must be a class template with parameters that exactly match the parameters of the template template parameter it substitutes. Default template arguments of a template template argument are ignored (but if the template template parameter has default arguments, they are considered during the instantiation of the template). This makes the following example invalid: #include <list> // declares: // namespace std { // template <typename T, // typename Allocator = allocator<T> > // class list; // } template<typename T1, typename T2, template<typename> class Container> // Container expects templates with only // one parameter class Relation { public: private: Container<T1> dom1; Container<T2> dom2; }; int main() { Relation<int, double, std::list> rel; // ERROR: std::list has more than one template parameter } The problem in this example is that the std::list template of the standard library has more than one parameter. The second parameter (which describes a so-called allocator ) has a default value, but this is not considered when matching std::list to the Container parameter. Sometimes, such situations can be worked around by adding a parameter with a default value to the template template parameter. In the case of the previous example, we may rewrite the Relation template as follows: #include <memory> template<typename T1, typename T2, template<typename T, typename = std::allocator<T> > class Container> // Container now accepts standard container templates class Relation { public: private: Container<T1> dom1; Container<T2> dom2; }; Clearly this isn't entirely satisfactory, but it enables the use of standard container templates. Section 13.5 on page 211 discusses possible future changes of this topic. The fact that syntactically only the keyword class can be used to declare a template template parameter is not to be construed as an indication that only class templates declared with the keyword class are allowed as substituting arguments. Indeed, "struct templates" and "union templates" are valid arguments for a template template parameter. This is similar to the observation that (just about) any type can be used as an argument for a template type parameter declared with the keyword class . 8.3.5 EquivalenceTwo sets of template arguments are equivalent when values of the arguments are identical one-for-one. For type arguments, typedef names don't matter: It is the type ultimately underlying the typedef that is compared. For integer nontype arguments, the value of the argument is compared; how that value is expressed doesn't matter. The following example illustrates this concept: template <typename T, int I> class Mix; typedef int Int; Mix<int, 3*3>* p1; Mix<Int, 4+5>* p2; // p2 has the same type as p1 A function generated from a function template is never equivalent to an ordinary function even though they may have the same type and the same name. This has two important consequences for class members:
|
Ru-Brd |