C++ 模版参数推断

来源:互联网 发布:电子期刊制作软件 编辑:程序博客网 时间:2024/04/29 08:55

16.2.1. Template Argument Deduction

To determine which functions to instantiate, thecompiler looks at each argument. If the corresponding parameter wasdeclared with a type that is a type parameter, then the compiler infersthe type of the parameter from the type of the argument. In the case of compare, both arguments have the same template type: they were eachdeclared using the type parameter T.

Inthe first call, compare(1, 0), those arguments are type int; in the second,compare, they have type double. The process of determining the types andvalues of the template arguments from the type of the function argumentsis called template argument deduction .

 

MultipleType Parameter Arguments Must Match Exactly

A template type parameter may be used as the type of more than one functionparameter. In such cases, template type deduction must generate the sametemplate argument type for each corresponding function argument. If thededuced types do not match, then the call is an error:


template <typename T>
int compare(const T& v1, const T& v2)
{
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}
int main()
{
short si;
// error: cannot instantiate compare(short, int)
// must be: compare(short, short) or
// compare(int, int)
compare(si, 1024);
return 0;
}


This call is in error because the arguments to comparedon't have the same type.The template argument deduced from the first argument is short; the onefor the second is int. These types don't match, so template argumentdeduction fails.
If the designer of comparewants to allow normal conversions on the arguments,then the function must be defined with two type parameters:


// argument types can differ, but must be compatible
template <typename A, typename B>
int compare(const A& v1, const B& v2)
{
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}


Now the user may supply arguments of different types:
short si;
compare(si, 1024); // ok: instantiates compare(short, int)


However, a <operator must exist that can compare values of those types.

 

LimitedConversions on Type Parameter Arguments

LimitedConversions on Type Parameter Arguments
Consider the following calls to compare:
short s1, s2;
int i1, i2;
compare(i1, i2); // ok: instantiate compare(int, int)
compare(s1, s2); // ok: instantiate compare(short, short)


The first call generates an instance of comparewith Tbound to int. A newinstance is created
for the second call, binding Tto short.


Had compare(int, int)been an ordinary nontemplate function, then the secondcall would
match that function. The shortarguments would be promoted (Section 5.12.2, p.180) to int.
Because compareis a template, a new function is instantiated with the typeparameter bound to
short.


In general, arguments are not converted to match an existing instantiation;instead, a new instance is generated. There are only two kinds of conversions that thecompiler will perform rather than generating a new instantiation:

const conversions: A function that takes a reference or pointer to a constcan becalled with a reference or pointer to nonconstobject, respectively, without generatinga new instantiation. If the function takes a nonreference type, then constis ignoredon either the parameter type or the argument. That is, the same instantiation will be usedwhether we pass a constor nonconstobject to a function defined to take a nonreferencetype. 

array or function to pointer conversions:If the template parameter is not areference type, then the normal pointer conversion will be applied to arguments of array orfunction type. An array argument will be treated as a pointer to its first element, and afunction argument will be treated as a pointer to the function's type.


As examples, consider calls to the functions fobjand fref. The fobjfunctioncopies its
parameters, whereas fref's parameters are references:


template <typename T> T fobj(T, T); // arguments are copied
template <typename T>
T fref(const T&, const T&); // reference arguments
string s1("a value");
const string s2("another value");
fobj(s1, s2); // ok: calls f(string, string), const is ignored
fref(s1, s2); // ok: non const object s1 converted to const reference
int a[10], b[42];
fobj(a, b); // ok: calls f(int*, int*)
fref(a, b); // error: array types don't match; arguments aren't converted topointers


In the first case, we pass a stringand a const stringas arguments. Even thoughthese types do not match exactly, both calls are legal. In the call to fobj, the argumentsare copied, so whether the original object is constdoesn't matter. In the call to fref, theparameter type is a reference to const. Conversion to constfor a reference parameter is one of theacceptable conversions, so this call is also okay.
In the next case, we pass array arguments in which the arrays are differentsizes. In the call to fobj, the fact that the arrays are different doesn't matter. Both arrays areconverted to pointers. The template parameter type in fobjis int*. The call to fref,however, is illegal. When the parameter is a reference (Section 7.2.4, p. 240), the arrays are notconverted to pointers. The types of aand bdon't match, so the call is in error.

 

Template Argument Deduction and Function Pointers

We can use a function template to initialize or assign to a function pointer (Section 7.9, p. 276 ). When we do so, the compiler uses the type of the pointer to instantiate a version of the template with the appropriate template argument(s).

As an example, assume we have a function pointer that points to a function returning an int that takes two parameters, each of which is a reference to a const int. We could use that pointer to point to an instantiation of compare: 


template <typename T> int compare(const T&, const T&);
// pf1 points to the instantiation int compare (const int&, const int&)
int (*pf1) (const int&, const int&) = compare;


The type of pf1is "pointer to function returning an  inttaking two parameters of type const int&." The type of the parameters in pf1determines the type of the template argument for T. The template argument for Tis int. The pointer pf1refers to the instantiation with Tbound to int.


It is an error if the template arguments cannot be determined from the function pointer type. For example, assume we have two functions named func. Each function takes a pointer to function argument. The first version of functakes a pointer to a function that has two const stringreference parameters and returns a string. The second version of functakes a pointer to a function taking two const intreference parameters and returning an int. We cannot use compareas an argument to func:


// overloaded versions of func; each take a different function pointer type
void func(int(*) (const string&, const string&));
void func(int(*) (const int&, const int&));
func(compare); // error: which instantiation of compare?


The problem is that by looking at the type of func's parameter, it is not possible to determine a unique type for the template argument. The call to funccould instantiate either of the following functions:


compare(const string&, const string&)
compare(const int&, const int&)
Because it is not possible to identify a unique instantiation for the argument to func, this call is a  compile-time (or link-time) error.

0 0
原创粉丝点击