C++函数模板

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

模板有函数模板和类模板。这篇文章讲函数模板。

函数模板例子。

template<typename T>
void Swap( T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}

下面用代码实现一下。 

#include<iostream>
//template <class T>
using namespace std;
namespace bit
{
	template<typename T>
	void swap(T& left, T& right)
	{
		T tmp = left;
		left = right;
		right = tmp;
	}
}
int main()
{
	int a = 1, b = 2;
	swap(a, b);
	cout << a << ' ' << b << endl;
	char c = 'b', d = 'c';
    swap(a, b);
	cout << c << ' ' << d << endl;
}

结果。

只写一个函数,但两种类型都能用。

 他们两个其实调用了两个不同的函数,两个函数栈帧的大小也不一样。我们实际调用的是模具生成的对应的函数。

模板是写给编译器的,编译器会推演模板,生成对应的函数,生成函数的过程叫函数模板的实例化。

如果如下调用,你们函数模板只会实例化一次。

但是像下面这样swap里面有两个类型,在上面模板下,编译器就会报错。

而且它不会强转,因为强转和转换只会在传参或赋值时发生。而这个报错是在传参或赋值前,传参和赋值是在实际调用时,而这里面在实际调用前编译器通过参数推出对应的模板,是在模板推演阶段报错的。

而且就算它到了强转那步也会有问题,因为模板形参是引用,而转化后的临时对象具有常性,是不能变的,相当于const T型,是不能传给T形的,因为那样此对象权限会扩大的,而也不能在形参定义时T&前加const,因为那样函数内就交换不了了。

但是,我们可以选择在推演之前进行强转。

#include<iostream>
using namespace std;
template<class T>

	template<typename T>
	T Add( const T& left,const T& right)
	{
		return left + right;
	}

int main()
{

	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add(a, (int)e) << endl;
}

但是只要去掉Add后面的const去掉,Add就会报错,因为强转后,模板通过强转后的那个隐式类型进行推演,而隐式类型具有常性,不加const相当于权限放大,此模板就不会匹配,推演也就不能完成。 

#include<iostream>
using namespace std;
template<class T>

	template<typename T>
	T Add( const T& left,T& right)
	{
		return left + right;
	}

int main()
{

	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add(a, (int)e) << endl;
}

 

 我们也可以显式实例化。

#include<iostream>
using namespace std;
template<class T>

	template<typename T>
	T Add( const T& left, const T& right)
	{
		return left + right;
	}

int main()
{

	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add<int>(a, e) << endl;
}

 

但不加const,也会报错。

 

 因为此时,显示实例化,相当于把T全部换为int,而e要传参就要隐式类型转换,因为隐式类型转换,临时变量具有常性,所以没有const,相当于权限放大,就会报错。

下面这样写也不行,因为e是强制类型转换的,同样具有常性,第二个T前也需要加const。

#include<iostream>
using namespace std;
template<class T>
	void Swap(T& left, T& right)
	{
		T tmp = left;
		left = right;
		right = tmp;
	}
	template<class T>
	T Add( T& left, T& right)
	{
		return left + right;
	}
int main()
{
	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add<int>(a, (int)e) << endl;
	
}

下面看下双变量模板。

#include<iostream>

using namespace std;
template<class T>
	template<typename T1, typename T2>
	T1 Add( T1& left,const T2& right)
	{
		return left + right;
	}

int main()
{
	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add(a, e) << endl;
}

因为返回值是T1类型,所以返回值是整形

 返回值改成T2返回值就变成浮点型了。

注意不能同时定义两个相同模板,但不同返回值类型的。

 两个参数也可以显示实例化,但下面这样只会显示实例化第一个参数。

#include<iostream>
using namespace std;
template<class T>

	template<typename T1, typename T2>
	T1 Add(const T1& left, const T2& right)
	{
		return left + right;
	}
int main()
{
	int a = 1, b = 2;
	double e = 1.1;
	cout <<Add<double>(a, e) << endl;
}

下面这么写并没有报错,说明两个参数的模板,Add<int>只会对第一个参数实例化为int型,因为如果对第二个参数也实例化了,那么e会隐式类型转换,T2前没有const,e的参数权限放大,会报错。 

 

 下图可以证明上面结论

 

模板和函数能同时存在。 说明函数和模板内部实现是有区别的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南种北李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值