Ru-Brd |
Function templates have two kinds of parameters:
You may have as many template parameters as you like. However, in function templates (unlike class templates) no default template arguments can be specified. [3] For example, you could define the max() template for call parameters of two different types:
template <typename T1, typename T2> inline T1 max (T1 const& a, T2 const& b) { return a < b ? b : a; } max(4,4.2) // OK, but type of first argument defines return type This may appear to be a good method to enable passing two call parameters of different types to the max() template, but in this example it has drawbacks. The problem is that the return type must be declared. If you use one of the parameter types, the argument for the other parameter might get converted to this type, regardless of the caller's intention . C++ does not provide a means to specify choosing "the more powerful type" (however, you can provide this feature by some tricky template programming, see Section 15.2.4 on page 271). Thus, depending on the call argument order the maximum of 42 and 66.66 might be the double 66.66 or the int 66. Another drawback is that converting the type of the second parameter into the return type creates a new, local temporary object. As a consequence, you cannot return the result by reference. [4] In our example, therefore, the return type has to be T1 instead of T1 const& .
Because the types of the call parameters are constructed from the template parameters, template and call parameters are usually related . We call this concept function template argument deduction . It allows you to call a function template as you would an ordinary function. However, as mentioned earlier, you can instantiate a template explicitly for certain types: template <typename T> inline T const& max (T const& a, T const& b); max<double>(4,4.2) // instantiate T as double In cases when there is no connection between template and call parameters and when template parameters cannot be determined, you must specify the template argument explicitly with the call. For example, you can introduce a third template argument type to define the return type of a function template: template <typename T1, typename T2, typename RT> inline RT max (T1 const& a, T2 const& b); However, template argument deduction does not match up return types, [5] and RT does not appear in the types of the function call parameters. Therefore, RT cannot be deduced . As a consequence, you have to specify the template argument list explicitly. For example:
template <typename T1, typename T2, typename RT> inline RT max (T1 const& a, T2 const& b); max<int,double,double>(4,4.2) // OK, but tedious So far, we have looked at cases in which either all or none of the function template arguments were mentioned explicitly. Another approach is to specify only the first arguments explicitly and to allow the deduction process to derive the rest. In general, you must specify all the argument types up to the last argument type that cannot be determined implicitly. Thus, if you change the order of the template parameters in our example, the caller needs to specify only the return type: template <typename RT, typename T1, typename T2> inline RT max (T1 const& a, T2 const& b); max<double>(4,4.2) // OK: return type is double In this example, the call to max<double> explicitly sets RT to double , but the parameters T1 and T2 are deduced to be int and double from the arguments. Note that all of these modified versions of max() don't lead to significant advantages. For the one-parameter version you can already specify the parameter (and return) type if two arguments of a different type are passed. Thus, it's a good idea to keep it simple and use the one-parameter version of max() (as we do in the following sections when discussing other template issues). See Chapter 11 for details of the deduction process. |
Ru-Brd |