• 模板参数自动推导


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

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

    图1 术语

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

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

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

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

    #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:模板的形参与模板函数的形参位置上不存在对应关系

    #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 与函数模板返回值相关的模板参数不能进行自动推导

    #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 欲推导的模板参数没有连续位于模板参数列表的尾部,导致中间出现了间隔,所以不能推导。

    #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了。

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








  • 相关阅读:
    责任链简单解析
    mysql实践一:SQL基础
    Aix6.1下su命令不能切换环境变量的问题
    maven 打包错误 Cannot access central in offline mode
    登陆并访问k8s的apiserver
    kubernetes 实践五:Service详解
    kubernetes1.16 配置 metrics-server
    kubernetes 实践四:Pod详解
    kubernetes 实践三:使用kubeadm安装k8s1.16.0
    kubernetes 实践二:kubectl命令使用
  • 原文地址:https://www.cnblogs.com/new0801/p/6177088.html
Copyright © 2020-2023  润新知