56.函数模板
1.什么是函数模版
函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板
2.怎么编写函数模版
//T代表泛型的数据类型,不是只能写T,
template<class T>//让编译器看到这句话后面紧跟着的函数里有T不要报错
void mySwap(T &a,T &b)
{
T tmp = a;
a = b;
b = tmp;
}
//可以这样定义函数模版
template<typename T>
void func2(T a,T b)
{
}
3.怎么使用函数模版
//T代表泛型的数据类型,不是只能写T,
template<class T>//让编译器看到这句话后面紧跟着的函数里有T不要报错
void mySwap(T &a,T &b)
{
T tmp = a;
a = b;
b = tmp;
}
template<class T>
void mySwap2()
{
}
//使用函数模版
void test02()
{
int a = 10;
int b = 20;
//1.编译器会根据实参来自动推导数据类型
mySwap(a,b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
char c = 'c';
//mySwap(a, c);err,数据类型要一致
//2.显示的指定类型
mySwap<int>(a, b);//<>用参数列表告诉编译器我只传int类
//mySwap<double>(a, b);//注意:指定类型,传入时不能不一致
mySwap<>(a,b);
//mySwap2<>();//err 调用时,必须让编译器知道泛型T具体是什么类型
}
4.编译器会对函数模版和类模版进行二次编译
//T代表泛型的数据类型,不是只能写T,
template<class T>//让编译器看到这句话后面紧跟着的函数里有T不要报错
void mySwap(T &a,T &b)//第一次编译
{
T tmp = a;
a= b;
b = tmp;
}
//使用函数模版
void test02()
{
int a = 10;
int b = 20;
//1.编译器会根据实参来自动推导数据类型
mySwap(a,b);//编译器在函数模版被调用时,进行第二次编译
/*
void mySwap(int &a,int &b)
{
int tmp = a;
a= b;
b = tmp;
}
*/
cout << "a=" << a << endl;
cout << "b=" << b << endl;
}
5.隐式转换
template<class T>
T func(T a, T b)
{
return a + b;
}
void test03()
{
int a = 10;
double b = 20.2;
//如果使用参数列表指定数据类型,那么实参中可以隐式转换
//如果转换成功,就调用,转换不成功就报错
cout << func<int>(10,20.2) << endl;
}
6.函数模板和普通函数的区别
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//普通函数
int myPlus(int a, int b)
{
return a + b;
}
template<class T>
int myPlus2(T a, T b)
{
return a + b;
}
void test()
{
int a = 10;
int b = 20;
char c = 'a';
//普通函数可以进行隐式转换
myPlus(a, c);
//函数模版不能直接的进行隐式转换
//myPlus2(a, c);
myPlus2<int>(a, c);//如果要进行隐性转换,必须加上参数列表
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
7.普通函数和函数模版的调用规则
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//普通函数
void myPlus(int a, int b)
{
cout << "普通函数" << endl;
}
template<class T>
void myPlus(T a, T b)
{
cout << "函数模版" << endl;
}
template<class T>
void myPlus(T a, T b, T c)
{
cout << "函数模版 T c" << endl;
}
//1.函数模版和普通函数可以重载
void test()
{
int a = 10;
int b = 20;
//2.如果普通函数和函数模版都可以实现的功能,普通函数优先调用
myPlus(a, b);
//3.可以使用<>空参数列表强制调用函数模版
myPlus<>(a, b);
//4.函数模版之间也可以进行重载
//5.如果函数模版可以产生更好的匹配,那么优先使用函数模版
char c1 = 'a';
char c2 = 'b';
myPlus(c1, c2);
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
8.函数模版的局限性和解决方法
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>
template<class T>
void func(T a, T b)
{
if (a > b)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
void test()
{
int arr[20];
int arr2[10];
func(arr, arr2);
}
class Maker
{
public:
Maker(string name,int age)
{
this->age = age;
this->name = name;
}
public:
string name;
int age;
};
template<class T>
void myfunc(T &a, T &b)
{
if (a > b)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
//不建议具体化函数模版,因为没有通用性
//具体化函数模版,注意上面的函数模版要有,才能具体化
template<>void myfunc<Maker>(Maker &a, Maker &b)
{
cout << "函数模版的具体化" << endl;
if (a.age > b.age)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
void test02()
{
Maker m1("aaa", 10);
Maker m2("bbb", 20);
myfunc(m1, m2);
}
int main()
{
test02();
system("pause");
return EXIT_SUCCESS;
}
参考资料
参考资料来源于黑马程序员