基本模板函数示例
不会使用函数模板的时候,一般情况下,我们要交换两个变量的值,我们会写下面的代码:
//如果交换的两个值是整型变量
void myswap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
//如果交换的两个值是浮点型变量
void myswap(double &a, double &b)
{
double temp;
temp = a;
a = b;
b = temp;
}
明明大部分代码是一样的,写两遍并不是一个优秀程序员的做法,使用模板函数可以提高代码的重用性。
在使用模板函数的情况下,代码可以简化为这样:
//模板函数,类型参数化,编写模版代码时可以忽略类型
//一个“template”只对一个函数生效
#include<iostream>
using namespace std;
template<class T> //告诉编译器,我下面写的是模板函数
void myswap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10, b = 20;
cout << a << " " << b << endl;
myswap(a, b); //这里就不需要考虑a,b的类型了
cout << a << " " << b << endl;
double c = 13.4, d = 7.32;
cout << c << " " << d << endl;
myswap(c, d);
cout << c << " " << d << endl;
return 0;
}
输出的结果应该是:
10 20
20 10
13.4 7.32
7.32 13.4
template的参数可以不止一个:
//而template<这里可以填写多个数据>
template<class T1, class T2>
void myswap(T1 &a, T1 &b, T2 c)
{
T1 temp;
temp = a;
a = b;
b = temp;
cout << c << endl;
}
模板函数和普通函数的区别
- 模版函数不允许自动类型转化
- 普通函数能够进行自动类型转化
- 模板函数必须严格类型匹配
#include<iostream>
using namespace std;
template<class T>
int myadd(T a, T b)
{
return a+b;
}
int myadd(int a, char b)
{
return a+b;
}
int main()
{
int a=10, b=20;
char c1='a', c2='b';
myadd(a, c1); //调用的是普通函数
myadd(a, b); //调用的是模板函数
myadd(c1, b); //调用的是普通函数
return 0;
}
模板函数和普通函数一起使用的规则
- 模板函数可以像普通函数那样进行函数重载
- c++编译器会优先考虑普通函数
- 如果模板函数可以产生一个更好的匹配,那么将选择模板函数
- 可以通过空模板实参列表的语法限定编译器,实现只能通过模板匹配
#include<iostream>
using namespace std;
template<class T>
void Print(T a, T b)
{
cout<<a+b<<endl;
cout<<"这是模板函数"<<endl;
}
void Print(int a, int b)
{
cout<<a+b<<endl;
cout<<"这是普通函数"<<endl;
}
int main()
{
int a=10, b=20;
Print(a, b); //c++编译器会优先考虑普通函数
return 0;
}
虽然a,b的值既符合普通函数又符合模板函数,但会优先考虑普通函数,代码结果如下:
30
这是普通函数
如果就是想调用模板函数的话,可以写 Print<>(a, b); 的形式
一般不这样做,除非有特别的需求。具体如下:
#include<iostream>
using namespace std;
template<class T>
void Print(T a, T b)
{
cout<<a+b<<endl;
cout<<"这是模板函数"<<endl;
}
void Print(int a, int b)
{
cout<<a+b<<endl;
cout<<"这是普通函数"<<endl;
}
int main()
{
int a=10, b=20;
Print<>(a, b); //c++编译器会优先考虑普通函数
return 0;
}
代码结果如下:
30
这是模板函数
模板函数的实现原理剖析
- 要分清楚模板函数和函数模板的区别
函数模板 —— 是一种模板,用于生成函数的模板
模板函数 —— 是一种函数,通过“函数模板”生成的函数
//函数模板(类似于加工厂的模具,无法直接使用)
template<class T>
int myadd(T a, T b)
{
retrun a+b;
}
//首先会生成一个模板函数(类似于加工好的零件)
//比如说,用两个float型变量调用的就会生产这样的函数
int myadd(float a, float b)
{
retrun a+b;
}
//最后才会被编译器调用
看一下在接下来的程序(包含函数模板),会生成多少个模板函数?
#include<iostream>
using namespace std;
template<class T>
int myadd(T a, T b)
{
retrun a+b;
}
int main()
{
int a=10, b=20, c=25;
float c=4.27, d=21.75;
myadd(a, b); //此时会产生“模板函数1”
myadd(c, d); //此时会产生“模板函数2”
myadd(b, c);
return 0;
}
没错,会生成以下两种模板函数
//“模板函数1”
int myadd(int a, int b)
{
retrun a+b;
}
//“模板函数2”
int myadd(float a, float b)
{
retrun a+b;
}
函数模板机制结论:
- 编译器并不是把函数模板处理成能够处理任何类型的函数
- 而是作为一个模板,通过具体类型产生不同的函数
- 编译器会对模板函数进行二次编译,第一次是在声明的地方对函数模板代码本身进行编译,第二次是在调用时对参数替换后的代码进行编译
函数模板的使用实例
利用冒泡排序对一串数字和字母排序:
#include<iostream>
using namespace std;
template<class T>
void Print(T* a, int len)
{
for (int i = 0; i < len; i++)
cout << a[i] << " ";
cout << endl;
}
template<class T>
void Sort(T* a, int len)
{
if (len < 2)
return;
T temp;
bool flag;
for (int i = 0; i <len-1; i++)
{
flag = 0;
for (int j = 0; j < len - i - 1; j++)
if (a[j] > a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
flag = 1;
}
if (flag = 0)
break;
}
}
int main()
{
int a[] = { 2,7,4,9,1,3,6 };
int len = sizeof(a) / sizeof(a[0]);
Print(a, len);
Sort(a, len);
Print(a, len);
char b[] = { 'd','f','r','v','a','u' };
len = sizeof(b) / sizeof(b[0]);
Print(b, len);
Sort(b, len);
Print(b, len);
return 0;
}
其输出的结果是:
2 7 4 9 1 3 6
1 2 3 4 6 7 9
d f r v a u
a d f r u v
而且只需要写一遍冒泡排序的代码,就可以实现数字和字母两种不同类型的排序。
以上是对模板函数初步解析,欢迎大家在评论区提出问题进行探讨!