1、函数模板基本概念
业务关系一样,处理的数据类型一致,数据类型参数化
Ø 函数模板定义由模板说明和函数定义组成 Ø 模板说明的类属参数必须在函数定义中至少出现一次 Ø 函数参数表中可以使用类属类型参数,也可以使用一般类型参数
|
template < 类型形式参数表 > //函数模板声明
类型 函数名 ( 形式参数表 ) //函数模板定义 { 语句序列 }
|
2、泛型编程函数使用的两种方法:
自动类型推导和具体调用类型参数列表 //template关键字告诉c++编译器,现在我要进行泛型编程, //typename 告诉c++编译器,T为数据类型,,,请你不要乱报错。。。。。 //T为数据类型,T为数据类型参数化,而已。。。 |
template<typename T> void myswap3(T &a, T &b) { T t = a; a = b; b = t; }; void main() { //泛型编程函数的使用方法有2种 int x = 1; int y = 2; //自动类型推导,, //myswap3(x, y); //具体类型调用, 参数列表 myswap3<int>(x, y); // myswap3<int,int>(x, y); char c1 = 'a'; char c2 = 'b'; myswap3<char>(c1, c2); system("pause"); } |
3、函数模板遇上函数重载
1、 函数模板可以像普通函数一样被重载 2、 C++编译器优先考虑普通函数 3 、如果函数模板可以产生一个更好的匹配,那么选择模板 4、 可以通过空模板实参列表的语法限定编译器只通过模板匹配
5、函数模板类型检测严格,不允许自动类型转化 6、普通函数能够进行自动类型转换
|
#include <iostream> using namespace std; int Max(int a, int b) { cout<<"int Max(int a, int b)"<<endl; return a > b ? a : b; } template<typename T> T Max(T a, T b) { cout<<"T Max(T a, T b)"<<endl; return a > b ? a : b; } template<typename T> T Max(T a, T b, T c) { cout<<"T Max(T a, T b, T c)"<<endl; return Max(Max(a, b), c); } void main() { int a = 1; int b = 2;
cout<<Max(a, b)<<endl; //2 C++编译器优先考虑普通函数 cout<<Max<>(a, b)<<endl; //4/通过空模板实参列表的语法限定编译器只通过模板匹配
cout<<Max(3.0, 4.0)<<endl;//3 如果函数模板可以产生一个更好的匹配,那么选择模板
cout<<Max(5.0, 6.0, 7.0)<<endl;
cout<<Max('a', 100)<<endl; //普通函数能够进行自动类型转换 system("pause"); } |
4、函数模板本质:
函数模板的深入理解
― 编译器并不是把函数模板处理成能够处理任意类型的函数 ― 编译器从函数模板通过具体类型产生不同的函数 ― 编译器会对函数模板进行两次编译 ―在声明的地方对模板代码本身进行编译 ―在调用的地方对参数替换后的代码进行编译
|
template<typename T> void swap2(T &a, T &b) { T t = a; a = b; b = t; } int main() { int x = 1; int y = 2; swap2<int>(x, y); { void swap2(int &a, int &b) { T t = a; a = b; b = t; } } //printf("\n%d, %d", x, y);
float x1 = 1.0; float y1 = 2.0; swap2<float>(x1, y1); {//函数调用的时候编译器相当于帮我们写了这个函数 void swap2(float &a, float &b) { T t = a; a = b; b = t; } } //printf("\n%f, %f", x1, y1); system("pause"); } |