二一、函数(四)1、推断函数模板返回类型
1)引:将以下函数改写为一个函数模板
int ave(int a,int b){ return (a+b)/2;}int ave(float a,fint b){ return (a+b)/2;}double ave(int a,float b){ return (a+b)/2;}
//参数和返回值为2种数据类型的函数模板template //模板定义时,可以定义多个类型T1 ave(T2 a, T1 b){return (a + b) / 2;}int main(){std::cout<<ave(100.55f, 200)<<std::endl;std::cout << ave(100.55f, 200) << std::endl; //可以强制性得指定模板中得参数类型}
//参数和返回值为3种数据类型的函数模板#include template //模板定义时,可以定义多个类型T3 ave(T2 a, T1 b){return (a + b) / 2;}int main(){std::cout << ave(100, 200.256f) << std::endl; //可以强制性得指定模板中得参数类型和返回值类型}注:可以将函数模板的返回值,设置在第一个位置,当不知道参数类型的时候,只指定函数类型即可#include template //模板定义时,可以定义多个类型TR ave(T2 a, T3 b){return (a + b) / 2;}int main(){std::cout << ave(100, 200.256f) << std::endl; //可以强制性得指定模板中得参数类型和返回值类型}
//如果传入的参数有一个可以确定参数,那么可以直接写明白参数的类型,不使用模板类型#include template //模板定义时,可以定义多个类型TR ave(T2 a, T3 b,int c) //第三个参数使用固定类型{return (a + b) / 2;}int main(){std::cout << ave(100, 200.256f,100) << std::endl; }
2)decltype回返回引用类型
#include template //模板定义时,可以定义多个类型auto bigger(T1 a, T2 b) //使用auto推断函数的返回值,或者decltype(auto) bigger(T1 a, T2 b),auto{return a>b?a:b;}int main(){char a = 56;int b = 50000000;std::cout << bigger(a, b);}//使用decltype(auto)可以返回引用类型,可以修改函数值#include template //模板定义时,可以定义多个类型decltype(auto) bigger(T1 &a, T2 &b) //使用auto推断函数的返回值,或者decltype(auto) bigger(T1 a, T2 b),auto{return a>b?a:b;}int main(){int a = 56;int b = 50000000;bigger(a, b) = -250; //可以修改值std::cout << b << std::endl;}
3)decltype不一定传回引用类型
#include template decltype(auto) bigger(T1& a, T2& b) {return a > b ? a : b; //类型不一样,会进行类型转化,类型转化以后,传出的值就不是一个引用类型了}int main(){float a = 56;int b = 50000000;//float& lx = b; //不是一个引用类型bigger(a, b); //可以修改值std::cout << b << std::endl;}
2、函数模板参数
1)函数模板默认参数(法一)
#include template //定义函数模板返回值的默认类型TR ave(T1 a, T2 b){return (a+b)/2; }int main(){std::cout << ave(100, 200) << std::endl; //使用默认的返回值类型std::cout << ave(100, 200) << std::endl; //使用指定的函数返回值类型}
2)函数模板默认参数(法二)
//将函数模板返回值默认类型指定为参数类型#include templateTR ave(T1 a,T2 b){return (a + b) / 2;}int main(){std::cout << ave(char(1), 200) << std::endl; //输出d}
3)非类型的模板参数
//非类型的函数模板参数#include template //非类型的函数模板参数,此处的max和min不是变量bool ChangeHp(T& hp,T damage){hp -= damage;if (hp > max)hp = max;//max=200; //报错,因为max不是变量,是函数模板参数,是常量return hp < min;}int main(){int hp = 2500;ChangeHp(hp, 100); //需要指定非类型的函数模板参数的值std::cout << hp << std::endl; //输出2000,因为最大值为2000}
//可以在函数模板定义时,就指定函数模板参数//非类型的函数模板参数#include template //模板定义时,直接指定非类型的函数模板参数的值bool ChangeHp(T& hp, T damage){hp -= damage;if (hp > max)hp = max;//max=200; //报错,因为max不是变量,是函数模板参数,是常量return hp < min;}int main(){int hp = 2500;ChangeHp(hp, 100); std::cout << hp << std::endl; }
3)非类型模板参数实现处理固定大小的数组
//计算数组中元素的和//处理不同元素个数的数组#include templateT ave(T(&ary)[count]) //并没有强制设置count的值{T all{};for (int i = 0; i < count; i++)all += ary[i];return all / count;}int main(){int a[5]{ 1,2,3,4,5 };std::cout << ave(a) << std::endl;}
3、函数模板的本质
编译器根据函数模板给定的参数,生成多个不同类型的函数
//C++#include template T ave(T a, T b){return a + b;}int main(){ave(100, 200);ave(short(100), short(200));}//函数调用汇编ave(100, 200);000B1991 68 C8 00 00 00 push 0C8h //200000B1996 6A 64 push 64h //100000B1998 E8 48 F8 FF FF call ave (0B11E5h) //函数调用000B199D 83 C4 08 add esp,8 ave(short(100), short(200));000B19A0 68 C8 00 00 00 push 0C8h 000B19A5 6A 64 push 64h 000B19A7 E8 06 F9 FF FF call ave (0B12B2h) //函数调用000B19AC 83 C4 08 add esp,8 //注:可以发现,调用同一个函数,调用的内存地址不一样,说明编译器根据函数模板,自动生成了两个ave()的函数
4、练习:排序工具
//需求:利用函数模板实现以下函数:能够给数组内的元素自动排序int a[5]{2302,5212,3654,9740,5200};Sort(a,5);short a[5]{2302,5212,3654,9740,5200};Sort(a,5);std::string a[5]{"abc","bcd","cde","fgh","ijk"}Sort(a,5)
//不使用函数模板#include void Swap(int& a,int& b){int tmp{ a };a = b;b = tmp;}void Sort(int* ary,unsigned count,bool Bigsort = true){for(int i=1;i<count;i++)for (int i = 1; i ary[i - 1]:ary[i] < ary[i - 1];if (bcase) Swap(ary[i], ary[i - 1]);}}int main(){int a[5]{ 2302,5212,3654,9740,5200 };Sort(a, 5);for (auto x : a)std::cout << x << std::endl;}
//使用函数模板实现上述功能#include templatevoid Swap(T& a, T& b){T tmp{ a };a = b;b = tmp;}templatevoid Sort(T* ary, unsigned count, bool Bigsort = true){for (T i = 1; i < count; i++)for (T i = 1; i ary[i - 1]:ary[i] < ary[i - 1];if (bcase) Swap(ary[i], ary[i - 1]);}}int main(){int a[5]{ 2302,5212,3654,9740,5200 };short b[5]{ 2302,5212,3654,9740,5200 };Sort(a, 5);for (auto x : a)std::cout << x << std::endl;std::cout << "+++++++++++++++++++++++++++++" << std::endl;Sort(b, 5);for (auto x : a)std::cout << x << std::endl;}