二、函数模板的显式实参
在某些情况下,不可能推断模板实参的类型。当函数的返回类型必须与形参表中所用的所有类型都不同时,最常出现这一问题。在这种情况下,有必要覆盖模板实参推断机制,并显式指定为模板形参所用的类型或值。
1、指定显式模板实参
如果函数形参类型不统一,该如何指定sum的返回类型?
template <class T, class U> ??? sum(T, U);
此时使用任一形参调用都一定会在某些时候失败:
sum(3, 4L); // 第二个类型较大,则应使用 U sum(T, U) sum(3L, 4); // 第一个类型较大,则应使用 T sum(T, U)
可以强制sum的调用者将较小的类型强制转换为希望作为结果使用的类型来解决此问题:
int i; short s; sum(static_cast<int>(s), i);
2、在返回类型中使用类型形参
指定返回类型的一种方式是引入第三个模板形参,它必须由调用者显式指定:
template <class T1,class T2,class T3> T1 sum(T2,T3);
有一个问题:没有实参的类型可用于推断T1的类型,相反,调用者必须在每次调用sum时为该类型显式提供实参。
int i; long lng; long val = sum<long>(i,lng);
这一调用显式指定T1的类型,编译器从调用中传递的实参推断T2,T3的类型。
【小结】
显式模板实参从左至右与对应模板形参相匹配,假如可以从函数形参推断,则只有结尾(最右边)形参的显式模板实参可以忽略。
如果这样编写sum函数:
template <class T1,class T2,class T3> T3 alternative_sum(T2,T1);
则总是必须为所有三个形参指定实参:
//没法识别模板实参的初始化 long val = alternative_sum<long>(i,lng); //Error long val2 = alternative_sum<long,int,long>(i,lng); //OK
3、显式实参与函数模板指针
可以使用显式模板实参的另一个例子是第16.2.1节中有二义性程序,通过使用显式模板实参能够消除二义性:
template <typename T> int compare(const T &,const T &); void func(int (*)(const string &,const string &)); void func(int (*)(const int &,const int &)); func(compare<string>);
像前面一样,需要在调用中传递compare实例给名为func的重载函数。只查看不同版本func的形参表来选择传递compare的哪个实例是不可能的,两个不同的实例都可能满足该调用。显式模板形参需要指出应使用哪个compare实例以及调用哪个func函数。
//P542 习题16.23 cout << max(3.14,5) << endl; //Error cout << max<double>(5.56,4) << endl; //OK
//习题16.24/25 template <typename T,typename U> int compare(const T &val1,const U &val2) { if (val1 < val2) return -1; if (val2 < val1) return 1; return 0; } int main() { cout << compare(1,static_cast<int>(3.14)) << endl; cout << compare(3.14,static_cast<double>(3)) << endl; cout << compare<int>(1,3.14) << endl; cout << compare<double>(1,3.14) << endl; cout << compare<string,string>("Hello","word") << endl; cout << compare(string("hello"),string("Word")) << endl; }
//习题16.26 template <typename T1,typename T2,typename T3> T1 sum(T2,T3); int main() { double dobj1,dobj2; float fobj1,fobj2; char cobj1,cobj2; sum(dobj1,dobj2); //Error sum<double,double,double>(fobj1,fobj2); //OK sum<int,int>(cobj1,cobj2); //OK sum<double,,double>(fobj1,fobj2); //Error }