函数模板,重载函数模板,模板的显式具体化,实例化

目录

一、函数模板应用场景

二、函数模板

 1.直白理解函数模板:函数模板就是建立一个通用的函数,其参数类型和返回类型不具体指定,用一个虚拟的类型来代表。

 2.函数模板的声明

3.函数模板的代码

 三、重载的模板

1.为什么要使用重载模板 

2.代码举例 

 四、显式具体化

1.为什么使用显式具体化 

 2.显示具体化的声明

 3.注意:使用显示具体化之前,必须有一个与其对应的模板函数。

 4.常规模板,具体化模板,非模板函数的优先调用顺序

 5.显示具体化的具体代码

 五、模板实例化(隐式实例和显式实例)

1. 什么是隐式实例化

2.什么是显式实例化

 3.在程序中使用函数来创建显式实例化。

六、总结 


一、函数模板应用场景

 假如需要编写一个程序交换两个数,但是在写程序过程中,可能需要定义多个函数,每个函数比较一种给定类型的值。

void Swap(int& a, int& b)
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}
void Swap(double& a, double& b)
{
	double temp;
	temp = a;
	a = b;
	b = temp;
}

 但是这两个函数的函数体一样,只是参数类型不一样,所有我们可以从这些函数中提炼出一个通用函数,而它又适用于多种不同类型的数据。此时就需要用到函数模板。

二、函数模板

 1.直白理解函数模板:函数模板就是建立一个通用的函数,其参数类型和返回类型不具体指定,用一个虚拟的类型来代表。

 2.函数模板的声明

第一种:template<typename 类型参数>
        返回类型 函数名(模板形参表)
例如:
       template <typename T>
       void Swap(T& a, T& b);

第二种:template<class 类型参数>
        返回类型 函数名(模板形参表)
例如:
       template <class T>
       void Swap(T& a, T& b);
template 是C++关键字,和函数一样,模板也有一系列参数。
类型参数一般用T这样的标识符来代表一个虚拟的类型,当使用函数模板时,会将类型参数具体化。
类型名T可以表示任意的int,double等类型

3.函数模板的代码

#include<iostream>
#include<stdio.h>
using namespace std;
template <typename T>
//类型名T可以表示任意的int,double等类型
void Swap(T & a, T & b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}
int main()
{
	int x = 2, y = 3;
	Swap(x, y);
	cout << x << " " << y << endl;//输出3 2
	char x1 = 'a', y1 = 'b';
	Swap(x1, y1);
	cout << x1 << " " << y1 << endl;//分别输出b a
	return 0;

}
int main()
{
	int d1[] = { 1,2,3,4,5 };
	int len = sizeof(d1)/sizeof(d1[0]);
	cout << len;
	return 0;
}

 三、重载的模板

1.为什么要使用重载模板 

需要多个对不同类型使用同一种算法的函数时,可使用模板。然而并非所有的类型都使用相同的算法。为满足这种需求,可以像重载常规函数定义那样重载模板定义。和常规重载一样,被重载的模板的函数特征标必须不同。 

2.代码举例 

在下面程序中定义了两个模板,原来模板的特征标为(T &,T &),新模板的特征标为(T *,T *,int)
或者(T [],T [],int),编译器见到第一个Swap()函数调用时,发现它有两个int参数,因此将它与原
来的模板匹配。但是第二次调用将两个int数组和一个int值作为参数,这与新模板匹配
#include<iostream>
template <typename T> //template <class T>与template <typename T> 一样
void Swap(T& a, T& b);//用于交换两个数

template <typename T>
void Swap(T* a, T* b, int n);//用于交换两个数组中的元素
using namespace std;

template <typename T>
void Swap(T& a, T& b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}
template <typename T>
void Swap(T a[],T b[],int n)
//void Swap(T* a, T* b, int n)(与上面形式等价)
{
	T temp;
	for (int i = 0; i < n; i++)
	{
		temp = a[i];
		a[i] = b[i];
		b[i] = temp;
	}
}
int main()
{
	int x1=1, y1=2;
	Swap(x1, y1);
	cout << x1 << " " << y1 << endl;


	int d1[] = { 1,2,3,4,5 };
	int d2[] = { 6,7,8,9,10 };
	int n = sizeof(d1)/sizeof(d1[0]);
	Swap(d1, d2,n);
	cout << d1[0] << " " << d1[1] << " " << d1[2] << " " << d1[3] << " " << d1[4] << endl;
	cout << d2[0] << " " << d2[1] << " " << d2[2] << " " << d2[3] << " " << d2[4] << endl;
	return 0;
}

 四、显式具体化

1.为什么使用显式具体化 

假设有如下模板函数:
template <typename T>
void f(T a,T b)
{...}
通常代码假定可执行哪些操作。例如,下面的代码假定定义了赋值,如果T为数组,这种假设不成了;
a = b;
同样,下面语句定义了<,但如果T为结构,该假设便不成立;
	if (a > b)
另外,为数组名定义了运算符>,但由于数组名为地址,因此它比较的是数组的地址,而这可能不是我们
所希望的。
下面的语句假定为类型T定义了乘法运算符,但如果T为数组、指针或结构,这种假设便不成立。
	T c = a * b;

所以为什么使用显式具体化:处理模板函数所不能处理的特殊情况。显式具体化显式具体化也是基于
函数模板的,只不过在函数模板的基础上,添加一个专门针对特定类型的、实现方式不同的具体化函数。

 2.显示具体化的声明

template <>[函数返回类型][函数模板名]<实际类型列表>(函数参数列表)
template <> void Swap<job>(job& j1, job& j2);//第一种声明方式
template <> void Swap(job& j1, job& j2);//第二种声明方式,两种声明方式等价
其中void对应返回类型,Swap是函数模板名,<>里面的job是实际类型,()里面的job是参数类型

 3.注意:使用显示具体化之前,必须有一个与其对应的模板函数。

比如:
template <typename T> //模板函数
void Swap(T & a, T & b);

template <> void Swap<job>(job& j1, job& j2);//显示具体化函数

 4.常规模板,具体化模板,非模板函数的优先调用顺序

非模板函数(普通函数) > 具体化模板函数 > 常规模板

 5.显示具体化的具体代码

#include<iostream>
using namespace std;
template <typename T>
void Swap(T& a, T& b);

struct job
{
	char name[40];
	double salary;
	int floor;
};
template <> void Swap<job>(job& j1, job& j2);


template<typename T>
void Swap(T &a,T &b)//常规模板
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

template <> void Swap<job>(job& j1, job& j2)// 具体化模板(此处只选择将salary交换)
{
	double temp_sal;
	temp_sal = j1.salary;
	j1.salary = j2.salary;
	j2.salary = temp_sal;

}

int main()
{
	/*int x1 = 1, y1 = 4;
	Swap(x1, y1);
	cout << x1 << " " << y1 << endl;*/

	struct job x2 = { "ZhangSan",100.1,2 };
	struct job y2 = { "LiSi",200.2,5 };
	Swap(x2, y2);
	cout << x2.name << " " << x2.salary << " " << x2.floor << endl;
	cout << y2.name << " " << y2.salary << " " << y2.floor << endl;
	return 0;
}

 五、模板实例化(隐式实例和显式实例)

1. 什么是隐式实例化

定义好函数模板后,当程序需要该函数模板定义的具体类型的函数时,编译器会根据该函数模板生成具体类型的函数定义,这种实例化方式被称为隐式实例化。 

例如:函数调用Swap(i, j)导致编译器生成Swap()的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板
实例是函数定义。同时编译器之所以知道需要进行定义,是由于程序调用Swap()函数时提供了int参数。

2.什么是显式实例化

直接命令编译器创建特定的实例,如Swap <int>()。其语法是,声明所需的种类——用<>符号指示类型,并且在声明前加上关键字template:

template[函数返回类型][函数模板名]<实际类型列表>(函数参数列表)
template void Swap <int>(int, int);

 3.在程序中使用函数来创建显式实例化。

#include<iostream>
using namespace std;
template <class T> //模板的声明
T add(T a, T b);

template <class T>//模板的定义
T add(T a, T b)
{
	return a + b;
}
int main()
{
	double x = 6.7;
	int y = 6;
	cout << add<double>(x, y) << endl;//输出8.5
}

 这里的模板和函数调用add(x,y)不匹配,因为该模板要求两个参数的类型相同都为T。但通过使用add<double>(x,y),可强制为double类型实例化,并将参数y强制转换为double类型,以便与函数add<double>(double ,double )的第二个参数匹配。

六、总结 

模板函数
template <typename T> void Swap(T &,T &);
template <class T> void Swap(T &,T &);
显式具体化
template <> void Swap<int>(int& , int&);
template <> void Swap(int& , int&);
显式实例化
template void Swap<int>(int &,int &);

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值