一、函数模板
由于相似功能的函数在使用不同类型参数时需要重新定义,所以可以采用C++中的函数模板来统一参数类型,使类型参数化,在编写代码时可以忽略类型。函数模板中,函数类型和形参类型并不直接确定,而是使用一个虚拟的类型对其进行定义,在调用时,函数会使用提供的实参类型取代虚拟类型。
二、函数模板格式
template<class T>或template<typename T>//为了让编译器区分是普通函数还是模板函数
同样,也可以定义多个参数,如template<class T1,class T2>//模板技术 类型参数化 编写代码可以忽略类型
注意:函数模板只对后面第一个函数生效
三、代码展示
不采用函数模板时,相似功能的函数需要重新定义,如下:
void MySwap(int &a,int &b)
{
int temp=a;
a=b;
b=a;
}
//double 类型
void MySwap(double &a,double &b)
{
double temp=a;
a=b;
b=a;
}
//问题:维护成本高
采用模板技术时,有两种使用方式,1是自动类型推导,2是显示的制定类型
#include <iostream>
using namespace std;
template<class T>//template<typename T>//只对后面第一个函数生效
void MySwap(T& a,T& b)
{
T temp=a;
a=b;
b=temp;
}
void test01()
{
int a=10;
int b=20;
//1 自动类型推导
cout<<"a:"<<a <<" b:"<<b<<endl;
MySwap(a,b);
cout<<"a:"<<a <<" b:"<<b<<endl;
double da=1.11;
double db=2.10;
cout<<"da:"<<da <<" db:"<<db<<endl;
MySwap(da,db);
cout<<"da:"<<da <<" db:"<<db<<endl;
//2 显示的制定类型
MySwap<int>(a,b);
cout<<"a:"<<a <<" b:"<<b<<endl;
}
int main()
{
test01();
return 0;
}
四、函数模板与普通函数一起调用时的规则
1、函数模板可以像普通函数那样被重载
//函数模板也可以像普通函数一样被重载
template<class T>
void Print(T a)
{
}
template<class T>
void Print(T a, T b)
{
}
2、同等情况下,C++编译器优先考虑普通函数;如果函数模板能够产生一个更好的匹配时,选模板;
#include <iostream>
using namespace std;
template <class T>
int MyAdd(T a,T b)
{
return a+b;
}
int MyAdd(int a,char c)
{
return a+c;
}
//普通函数可以进行 自动类型转换 同等情况下,优先考虑普通函数
//函数模板必须严格类型匹配 函数模板能产生一个更好的匹配时,选模板
void test02()
{
int a=10;
int b=20;
char c1='a';
char c2='b';
MyAdd<>(a,b);//强制调用模板
MyAdd(a,c1);//调用普通函数
MyAdd(a,b);//调用模板
MyAdd(c1,b);//调用普通函数 可进行类型转换
}
3、可以通过空模板实参列表的语法限定编译器只能通过模板匹配,如MyAdd<>(a,b);
五、函数模板实现原理
其中c++编译过程如下图所示
函数模板调用过程,在调用的过程中生成模板函数,方框中将生成两个模板函数,调用三次。
函数模板机制结论:
1、编译器并不是把函数模板处理成能够处理任何类型的函数
2、函数模板通过具体类型产生不同的函数
3、编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。