在哪些情况下,需要具体指定模板的参数`types`?

时间:2011-08-29 05:37:48

标签: c++ templates

// 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)

一种情况可能是您需要指定返回类型。

还有其他需要手动指定参数类型的情况吗?

4 个答案:

答案 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 已经模仿了两种类型:mR,我们在调用它时只提供了一种类型。也就是说,我们写了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,了解函数调用中参数的演绎细节。