Function templates have two kinds of parameters:
-
Template parameters, which are declared in angle brackets before the function template name:
-
Call parameters, which are declared in parentheses after the function template name:
You may have as many template parameters as you like. However,
in function templates (unlike class templates) no default template arguments can
be specified. For example, you could define the
max() template for call parameters of two different types:
This restriction is mainly the result of a historical glitch in the development of function templates. There are probably no technical hindrances to implementing such a feature in modern C++ compilers, and in the future it will probably be available
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. 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. In our example, therefore, the return type
has to be T1 instead of T1 const&.
You are not allowed to return values by reference if they are local to a function because you'd return something that doesn't exist when the program leaves the scope of this function.
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:
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:
However, template argument deduction does not match up return
types, 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:
Deduction can be seen as part of overload resolution—a process that is not based on selection of return types either. The sole exception is the return type of conversion operator members.
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:
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 coming posts for details of the deduction process.
No comments:
Post a Comment