// Function declaration.
template <typename T1,
typename T2,
typename RT> RT max (T1 a, T2 b);
// Function call.
max <int,double,double> (4,4.2)
// Function call.
max <int> (4,4.2)
一种情况可能是您需要指定返回类型。
还有其他需要手动指定参数类型的情况吗?
答案 0 :(得分:10)
(1)当对该函数没有参数并且它仍然是template
类型时,您可能必须明确指定参数
template<typename T>
void foo ()
{}
用法:
foo<int>();
foo<A>();
(2)您希望区分值和参考。
template<typename T>
void foo(T obj)
{}
用法:
int i = 2;
foo(i); // pass by value
foo<int&>(i); // pass by reference
(3)需要推断其他类型而不是自然类型。
template<typename T>
void foo(T& obj)
{}
用法:
foo<double>(d); // otherwise it would have been foo<int>
foo<Base&>(o); // otherwise it would have been foo<Derived&>
(4) 为单个模板参数提供了两种不同的参数类型
template<typename T>
void foo(T obj1, T obj2)
{}
用法:
foo<double>(d,i); // Deduction finds both double and int for T
答案 1 :(得分:7)
如果函数模板参数出现在函数参数列表中,则无需指定模板参数。例如,
template<typename T>
void f(const T &t) {}
此处T
是模板参数,它出现在函数参数列表中,即const T &t
。因此,调用此函数时无需指定模板参数:
f(10); //ok
由于10
的类型为int
,因此编译器可以从中推断模板参数T,并{{1} }变成T
。
请注意,由于类型推导是使用函数参数的信息完成的,因此其名为template argument deduction。现在继续阅读。
如果模板参数未出现在函数参数列表中,则必须提供模板参数。例如:
int
注意template<typename T>
void g(const int &i) {}
与g()
不同。现在f()
没有出现在函数参数列表中。所以:
T
请注意,如果函数模板也在返回类型上进行模板化,并且返回类型与出现在函数参数列表中的类型不同,那么您必须提供返回类型:
g(10); //error
g<double>(10); //ok
由于返回类型template<typename T>
T h(const T &t) {}
与函数参数相同,因此可以从函数参数中输入类型:
T
但如果你这样:
h(10); //ok - too obvious now
然后,
template<typename R, typename T>
R m(const T &t) {}
请注意,即使功能模板m(10); //error - only T can be deduced, not R
m<int>(10); //ok
已经模仿了两种类型:m
和R
,我们在调用它时只提供了一种类型。也就是说,我们写了T
而不是m<int>(10)
。写下之后没有什么害处,但如果你不这样做,那就没关系。但有时候你要指定两者,即使可以推导出一种类型m<int,int>(10)
。当类型参数的顺序不同时,如下所示:
T
现在,你要提供两种类型:
template<typename T, typename R> //note the order : its swapped now!
R n(const T &t) {}
这里的新功能是:类型参数的顺序也很重要。
无论如何,这仅涵盖基本概念。现在我建议你阅读一些关于模板的好书,学习关于类型演绎的所有高级内容。
答案 2 :(得分:2)
通常,当编译器无法自行解决时,您需要显式指定类型。正如您所提到的,这通常在返回类型被模板化时发生,因为无法从函数调用中推断出返回类型。
模板类具有相同的问题 - 实例化std::vector
无法让编译器确定向量存储的类型,因此您需要指定std::vector<int>
等等。
类型解析仅在函数参数的情况下执行,因此可能更容易将其视为特殊情况;通常,编译器无法猜测要使用的类型。
答案 3 :(得分:2)
简单的答案是,当编译器本身不能推导类型时,或者当您希望使用与特定类型不同的特定类型实例化模板时,您需要提供类型。编译器将演绎。
当编译器无法推断出类型时,存在不同的情况。因为类型推导仅应用于参数(如重载解析的情况),如果返回类型不显示为可推导的参数,则必须指定它。但是在其他情况下类型扣除不起作用:
template <typename R> R f(); // Return type is never deduced by itself
template <typename T>
T min( T const & lhs, T const & rhs );
min( 1, 2 ); // Return type is deducible from arguments
min( 1.0, 2 ); // T is not deducible (no perfect match)
min<double>( 1.0, 2 ); // Now it is ok: forced to be double
min<double>( 1, 2 ); // Compiler will deduce int, but we want double
template <typename T>
void print_ptr( T* p );
print_ptr<void>( 0 ); // 0 is a valid T* for any T, select manually one
template <typename T>
T min( T lhs, T rhs );
int a = 5, b = 7;
min<int&>(a,b)++; // Type deduction will drop & by default and call
// min<int>(a,b), force the type to be a reference
template <typename C>
typename C::value_type
min_value( typename C::const_iterator begin, typename C::const_iterator end );
std::vector<int> v;
min_value<std::vector<int> >( v.begin(), v.end() );
// Argument type is not deducible, there are
// potentially infinite C that match the constraints
// and the compiler would be forced to instantiate
// all
可能有更多原因导致参数类型无法推导出来,您可以查看标准中的§14.8.2.1,了解函数调用中参数的演绎细节。