模板参数自动推导

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

    为了表达明确,我们先来看一下图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了。

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








posted on 2014-07-11 12:54  三少爷的剑123  阅读(218)  评论(0编辑  收藏  举报

导航