打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
2.11 模板函数的默认模板参数

2.11 模板函数的默认模板参数

类别:所有人

在C++11中模板和函数一样,可以有默认的参数。这就带来了一定的复杂性。我可以通过代码清单2-26所示的这个简单的模板函数的例子来回顾一下函数模板的定义。

代码清单2-26

  1. #include iostream> 
  2. using namespace std;  
  3.  
  4. // 定义一个函数模板  
  5. template typename T> void TempFun(T a) {  
  6.     cout  a  endl;  
  7. }  
  8.  
  9. int main() {  
  10.     TempFun(1);     // 1, (实例化为TempFunconst int>(1))  
  11.     TempFun('1');   // 1, (实例化为TempFunconst char *>('1'))  
  12. }  
  13. // 编译选项:g++ 2-11-1.cpp  
  14.  

在代码清单2-26中,当编译器解析到函数调用fun(1)的时候,发现fun是一个函数模板。这时候编译器就会根据实参1的类型const int推导实例化出模板函数void TempFun(int),再进行调用。相应的,对于fun('1')来说也是类似的,不过编译器实例化出的模板函数的参数的类型将是const char *。

函数模板在C++98中与类模板一起被引入,不过在模板类声明的时候,标准允许其有默认模板参数。默认的模板参数的作用好比函数的默认形参。然而由于种种原因,C++98标准却不支持函数模板的默认模板参数。不过在C++11中,这一限制已经被解除了,我们可以看看下面这个例子,如代码清单2-27所示。

代码清单2-27

  1. void DefParm(int m = 3) {}  // c++98编译通过,c++11编译通过  
  2. template typename T = int> 
  3.     class DefClass {};      // c++98编译通过,c++11编译通过  
  4. template typename T = int> 
  5.     void DefTempParm() {};  // c++98编译失败,c++11编译通过  
  6. // 编译选项:g++ -c -std=c++11 2-11-1.cpp  
  7.  

可以看到,DefTempParm函数模板拥有一个默认参数。使用仅支持C++98的编译器编译,DefTempParm的编译会失败,而支持C++11的编译器则毫无问题。不过在语法上,与类模板有些不同的是,在为多个默认模板参数声明指定默认值的时候,程序员必须遵照“从右往左”的规则进行指定。而这个条件对函数模板来说并不是必须的,如代码清单2-28所示。

代码清单2-28

  1. templatetypename T1, typename T2 = int> class DefClass1;  
  2. templatetypename T1 = int, typename T2> class DefClass2;   // 无法通过编译  
  3.  
  4. templatetypename T, int i = 0> class DefClass3;  
  5. templateint i = 0, typename T> class DefClass4;            // 无法通过编译  
  6.  
  7. templatetypename T1 = int, typename T2> void DefFunc1(T1 a, T2 b);  
  8. templateint i = 0, typename T> void DefFunc2(T a);  
  9. // 编译选项:g++ -c -std=c++11 2-11-2.cpp  
  10.  

从代码清单2-28中可以看到,不按照从右往左定义默认类模板参数的模板类DefClass2和DefClass4都无法通过编译。而对于函数模板来说,默认模板参数的位置则比较随意。可以看到DefFunc1和DefFunc2都为第一个模板参数定义了默认参数,而第二个模板参数的默认值并没有定义,C++11编译器却认为没有问题。

函数模板的参数推导规则也并不复杂。简单地讲,如果能够从函数实参中推导出类型的话,那么默认模板参数就不会被使用,反之,默认模板参数则可能会被使用。我们可以看看下面这个来自于C++11标准草案的例子,如代码清单2-29所示。

代码清单2-29

  1. template class T, class U = double> 
  2. void f(T t = 0, U u = 0);  
  3.  
  4. void g() {  
  5.     f(1, 'c');      // fint,char>(1,'c')  
  6.     f(1);           // fint,double>(1,0), 使用了默认模板参数double  
  7.     f();            // 错误: T无法被推导出来  
  8.     fint>();       // fint,double>(0,0), 使用了默认模板参数double  
  9.     fint,char>();  // fint,char>(0,0)  
  10. }  
  11. // 编译选项:g++ -std=c++11 2-11-3.cpp  
  12.  

在代码清单2-29中,我们定义了一个函数模板f,f同时使用了默认模板参数和默认函数参数。可以看到,由于函数的模板参数可以由函数的实参推导而出,所以在f(1)这个函数调用中,我们实例化出了模板函数的调用应该为f(1,0),其中,第二个类型参数U使用了默认的模板类型参数double,而函数实参则为默认值0。类似地, f()实例化出的模板函数第二参数类型为double,值为0。而表达式f()由于第一类型参数T的无法推导,从而导致了编译的失败。而通过这个例子我们也可以看到,默认模板参数通常是需要跟默认函数参数一起使用的。

还有一点应该强调一下,模板函数的默认形参不是模板参数推导的依据。函数模板参数的选择,总是由函数的实参推导而来的,这点读者在使用中应当注意。

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C ++template模板 学习笔记
C++ Template1 SFINEA in C++
C++多态性(静多态和动多态)
你们要的C++20特性,今天安排了!
STL C++编译中的 延迟编译
C++函数模板
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服