函数模板
一、函数模板的定义
基本语法:
template <模板函数参数列表>
返回类型 函数模板名(函数参数列表)
{ 函数体 }
注:
1、模板参数列表不可为空,可以是一个或多个类型参数(如:typename
T1,typename T2),也可以是非类型参数(如: int size),这种非类型参数当
作常量使用,而且在实参化时,需要用一个常量表达式(或常量)赋值。
2、非类型参数,可以在函数体的定义中当作常量使用,也可以当作函数的
默认实参。
3、类型参数可以用该类型声明函数的返回值类型,形参,临时变量
4、非类型的模板 参数的值必须是一个常量,而且是编译时就能确认的常量
包括字面常量、符号常量(const 常量)。
二、函数模板的使用
实例化:在使用函数模板之前,必须先确定模板参数,可由用户明确确指定,也可
由编译器自行推导。
1、实例化化函数模板(生成一个真正意义上的函数)
:根据一组或者更多具体类型或值构造具体的函数
2、取函数模板的地址
:因为函数模板并不是真正的函数,所以其本身没有地址,所以取函数模板的地址
时,也会导致函数模板的实例化。
三、实参推演
:当函数模板被调用时,编译器根据函数的实参决定模板实参的过程。
1、多个函数的实参可以参加同一个模板实参的推演过程,如果模板参数表中
出现多次,则每个推演出来的类型必须是相同的。
2、显示指定函数模板的实参
3、显示声明实例:
template 返回类型 模板名<模板实参列表>(函数形参列表);
注:推演过程中,只要能够将函数实参转换成相应的模板实参即可。
下列3种的类型转换是允许的。
a、左值=右值
当左值可以做右值使用时,如:指针=数组名。
b、限定符修饰转换
const volatile
:普通的指针变量可以转换为const或volatile指针。
c、到基类的转换
实参:子类对象
模板形参:基类对象。
四、函数模板的特化
同一个模板针对特定数据类型,改变函数体代码逻辑,如数组的求和中 char类型的
处理。
基本语法:
template <>
返回类型 模板名<模板实参列表>(函数参数列表)
{
函数体。
}
注:
1、特化时需要非特化模板函数已经声明过了。
2、template <> 括号不可加原来普通非特化模板函数中的模板形参。
类模板的偏特化。才需要加参数。
函数模板的偏特化严格的来说,函数模板并不支持偏特化,但
由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
<也可添加模板参数>
五、函数模板的重载
几点要求:
模板名称相同
模板形参相同
函数形参相同(函数返回类型不参与区分)
六、函数模板的编译
:2种编译方式:包含编译方式,
1、包含编译方式
模板在头文件中定义,如果某个源文件需要实例化模板,就包含模板所在的头文件。
2、分离编译方式
头文件是函数模板的声明,模板定义则放在别处的的源文件中,在定义模板的
源文件中,在关键字template前加上export,表示声明一个可导出的函数
模板。在使用该模板函数的文件中包含头文件。
源程序:
#include <iostream>
using namespace std;
//模板函数的定义 ,类型参数和非类型参数
template <typename T,int size>
T min(T (&arr)[size])
{
T value=arr[0];
for(int i=0;i<size;i++)
{
if(arr[i]<value)
{
value=arr[i];
}
}
return value;
}
template float min<float,5>(float (&)[5]);//不能在函数内部
//特化模板 就是指定函数形参的类型,而且需要非特化模板已经在这之前声明。
template <>
char min<char ,10>(char (&arr)[10])
{
char value=arr[0];
for(int i=0;arr[i]!='\0';i++)
{
if(arr[i]<value)
{
value=arr[i];
}
}
return value;
}
template char min</*对应特化模板新添形参列表*/>(char (&arr)[10]);
int main()
{
int arr[10]={2,4,6,46,2,345,7,9,2,1};
float farr[5]={12.34,23.5,345.2,45.2,12.0};
char carr[]="QBCDERTGA";
const int arrsize=10;
//使用模板函数时都需要实例化,
//1、直接调用模板函数,让系统编译程序自动选择进行实参扮演,并实例化,继而调用
cout<<min(arr)<<endl;
//2、直接调用模板函数,指定模板实参列表,系统编译程序根据所给模板实参实例化
cout<<min<int,arrsize/*这里必须是常量表达式*/>(arr)<<endl;
//3、先显示指定模板函数实参,实例化一个模板函数,也就是真正的实现一个函数,并申请内存空间。
//同种类型的实参列表,只能实例化一次。见33行
//使用
cout<<min(farr)<<endl;
//使用特化模板,也可以像以上模板一样使用,三种方法
cout<<min(carr)<<endl;
return 0;
}
//同样函数模板也可以像一般的函数一样重载:模板名称相同,模板形参相同,函数形参不同。
程序输出结果:
1
1
12
A