c++模板参数自动推导

来源:互联网 发布:fbreader源码画线功能 编辑:程序博客网 时间:2024/05/21 10:04

    上次,我们看了什么是模板函数,今天,我们就从这个模板函数入手,继而引出一个新的知识点-模板参数自动推导。为了介绍清楚什么是模板参数自动推导,我们先定义几个术语,通过这些术语来描述比较方便,这些术语是:模板形参,模板实参,模板函数形参,模板函数实参。

    为了表达明确,我们先来看一下图1,图1中指出了什么是模板参数,模板实参,模板函数形参,模板函数实参。

图1 术语

    就像图1所示,template<>中的参数为模板形参,get_max_type()中的参数为模板函数形参。当我们调用这个模板函数的时候,char,int为模板实参,’a’,10为模板函数实参。

    从图1的代码中,我们可以看到模板的形参和模板函数的形参在位置上,具有一定的对应关系,因此,当我们调用模板函数的时候,C++编译器会自动根据模板函数的实参来推测模板的实参,我们将这种机制成为模板参数自动推导。

    根据模板参数自动推导的规则,图1中的代码可以改写为例1,如下:

例1:根据模板参数自动推导,省略模板实参

[cpp] view plain copy
print?
  1. #include<iostream>  
  2. using namespace std;  
  3. template<typename T1, typename T2>  
  4. int get_max_type(T1 a, T2 b)  
  5. {  
  6.     int nMax = 0;  
  7.     if (sizeof(T1) >= sizeof(T2))  
  8.     {  
  9.         nMax = sizeof(T1);  
  10.     }  
  11.     else  
  12.     {  
  13.         nMax = sizeof(T2);  
  14.     }  
  15.   
  16.     return nMax;  
  17. }  
  18. int main(int argc, char * argv[])  
  19. {  
  20.     int nMax = get_max_type(‘a’, 10);  
  21.     cout<<”max:”<<nMax<<endl;  
  22.     return 0;  
  23. }  
#include<iostream>using namespace std;template<typename T1, typename T2>int get_max_type(T1 a, T2 b){    int nMax = 0;    if (sizeof(T1) >= sizeof(T2))    {        nMax = sizeof(T1);    }    else    {        nMax = sizeof(T2);    }    return nMax;}int main(int argc, char * argv[]){    int nMax = get_max_type('a', 10);    cout<<"max:"<<nMax<<endl;    return 0;}
    在例1中,因为模板形参T1和T2,在位置上,与模板函数形参a和b,具有一一对应的关系,因此,当我们调用模板函数get_max_type的时候,就可以省略模板实参char和int的输入,使调用模板函数和调用普通函数一样方便。

    虽然模板参数自动推导非常方便,但并不是所有的情况都可以使用模板参数自动推导。使用模板参数自动推导需要满足3个条件:

    1、模板的形参必须与模板函数的形参在位置上存在一一对应的关系

    2、与模板函数返回值相关的模板参数无法进行自动推导

    3、需要推导的模板参数必须是连续位于模板参数列表的尾部,中间不能有不可推导的模板参数。

    下面,我们通过几个例子来一一说明这3个条件的重要性。

例2:模板的形参与模板函数的形参位置上不存在对应关系

[cpp] view plain copy
print?
  1. #include<iostream>  
  2. using namespace std;  
  3. template<typename T1, typename T2>  
  4. int get_max_type(char a, int b)  
  5. {  
  6.     int nMax = 0;  
  7.     if (sizeof(T1) >= sizeof(T2))  
  8.     {  
  9.         nMax = sizeof(T1);  
  10.     }  
  11.     else  
  12.     {  
  13.         nMax = sizeof(T2);  
  14.     }  
  15.   
  16.     return nMax;  
  17. }  
  18. int main(int argc, char * argv[])  
  19. {  
  20.     int nMax = get_max_type(‘a’, 10);  
  21.     cout<<”max:”<<nMax<<endl;  
  22.     return 0;  
  23. }  
#include<iostream>using namespace std;template<typename T1, typename T2>int get_max_type(char a, int b){    int nMax = 0;    if (sizeof(T1) >= sizeof(T2))    {        nMax = sizeof(T1);    }    else    {        nMax = sizeof(T2);    }    return nMax;}int main(int argc, char * argv[]){    int nMax = get_max_type('a', 10);    cout<<"max:"<<nMax<<endl;    return 0;}
    在例2中,函数模板的形参T1和T2与函数模板的函数形参char和int之间,在位置上,没有任何对应关系,因此在调用这个函数模板的时候,不能进行模板参数自动推导。否则,会出现编译错误,如图2:

图2 vc2013中的编译错误

例3 与函数模板返回值相关的模板参数不能进行自动推导

[cpp] view plain copy
print?
  1. #include<iostream>  
  2. using namespace std;  
  3. template<typename T1, typename T2>  
  4. T1 get_max_type(char a, T2 b)  
  5. {  
  6.     int nMax = 0;  
  7.     if (sizeof(T1) >= sizeof(T2))  
  8.     {  
  9.         nMax = sizeof(T1);  
  10.     }  
  11.     else  
  12.     {  
  13.         nMax = sizeof(T2);  
  14.     }  
  15.   
  16.     return nMax;  
  17. }  
  18. int main(int argc, char * argv[])  
  19. {  
  20.     int nMax = get_max_type(‘a’, 10);  
  21.     cout<<”max:”<<nMax<<endl;  
  22.     return 0;  
  23. }  
#include<iostream>using namespace std;template<typename T1, typename T2>T1 get_max_type(char a, T2 b){    int nMax = 0;    if (sizeof(T1) >= sizeof(T2))    {        nMax = sizeof(T1);    }    else    {        nMax = sizeof(T2);    }    return nMax;}int main(int argc, char * argv[]){    int nMax = get_max_type('a', 10);    cout<<"max:"<<nMax<<endl;    return 0;}
    例3中,函数模板形参T2在位置上与函数模板的函数形参b具有一一对应的关系,并且位于模板参数列表的尾部,因此,可以进行自动推导;但是,模板形参T1在位置上与模板的函数形参没有任何对应关系,因此,不能进行自动推导;虽然模板形参T1和模板的函数返回值在位置上具有一一对应关系,但是,仍然不可以。具体编译效果如图3:

图3 vc2013中的编译错误

例4 欲推导的模板参数没有连续位于模板参数列表的尾部,导致中间出现了间隔,所以不能推导。

[cpp] view plain copy
print?
  1. #include<iostream>  
  2. using namespace std;  
  3. template<typename T1, typename T2, typename T3, typename T4>  
  4. int func(T1 v1, T3 v3, T4 v4)  
  5. {  
  6.     return 0;  
  7. }  
  8.   
  9. void main()  
  10. {  
  11.     int nTemp = 0;  
  12.     nTemp = func<, intintint>(1, 2, 3);  
  13. }  
#include<iostream>using namespace std;template<typename T1, typename T2, typename T3, typename T4>int func(T1 v1, T3 v3, T4 v4){    return 0;}void main(){    int nTemp = 0;    nTemp = func<, int, int, int>(1, 2, 3);}
    在例4中,模板参数T1虽然与模板的函数参数v1的类型存在位置上的对应关系,但是由于T2的出现,导致T1不能和T3、T4连续位于模板参数列表的尾部,所以当我们使用这个函数模板的时候,在模板参数的实参-<,int,int,int>中,T2必须填写,这样,如果省略T1,就只剩下了一个‘,’,这样就会导致编译错误;如果连‘,’也不写,即func<int,int,int>,那么,自动推导的参数就是T4,而不是T1了。

    今天,我们主要讲解了什么是模板参数自动推导以及自动推导的充要条件,希望大家能够多多实践例子中的代码,加深对模板参数自动推导的理解。