二一、函数(四)
二一、函数(四)
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<typename T1,typename T2> //模板定义时,可以定义多个类型
T1 ave(T2 a, T1 b)
{
return (a + b) / 2;
}
int main()
{
std::cout<<ave(100.55f, 200)<<std::endl;
std::cout << ave<float,int>(100.55f, 200) << std::endl; //可以强制性得指定模板中得参数类型
}
//参数和返回值为3种数据类型的函数模板
#include <iostream>
template<typename T1, typename T2,typename T3> //模板定义时,可以定义多个类型
T3 ave(T2 a, T1 b)
{
return (a + b) / 2;
}
int main()
{
std::cout << ave<int,float,double>(100, 200.256f) << std::endl; //可以强制性得指定模板中得参数类型和返回值类型
}
注:可以将函数模板的返回值,设置在第一个位置,当不知道参数类型的时候,只指定函数类型即可
#include <iostream>
template<typename TR, typename T2,typename T3> //模板定义时,可以定义多个类型
TR ave(T2 a, T3 b)
{
return (a + b) / 2;
}
int main()
{
std::cout << ave<double>(100, 200.256f) << std::endl; //可以强制性得指定模板中得参数类型和返回值类型
}
//如果传入的参数有一个可以确定参数,那么可以直接写明白参数的类型,不使用模板类型
#include <iostream>
template<typename TR, typename T2,typename T3> //模板定义时,可以定义多个类型
TR ave(T2 a, T3 b,int c) //第三个参数使用固定类型
{
return (a + b) / 2;
}
int main()
{
std::cout << ave<double>(100, 200.256f,100) << std::endl;
}
2)decltype回返回引用类型
#include <iostream>
template<typename T1, typename T2> //模板定义时,可以定义多个类型
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 <iostream>
template<typename T1, typename T2> //模板定义时,可以定义多个类型
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 <iostream>
template<typename T1, typename T2>
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 <iostream>
template<typename TR=int,typename T1, typename T2> //定义函数模板返回值的默认类型
TR ave(T1 a, T2 b)
{
return (a+b)/2;
}
int main()
{
std::cout << ave(100, 200) << std::endl; //使用默认的返回值类型
std::cout << ave<float>(100, 200) << std::endl; //使用指定的函数返回值类型
}
2)函数模板默认参数(法二)
//将函数模板返回值默认类型指定为参数类型
#include <iostream>
template<typename T1, typename T2,typename TR = T1>
TR ave(T1 a,T2 b)
{
return (a + b) / 2;
}
int main()
{
std::cout << ave(char(1), 200) << std::endl; //输出d
}
3)非类型的模板参数
//非类型的函数模板参数
#include <iostream>
template<int max, int min,typename T> //非类型的函数模板参数,此处的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<2000,1000>(hp, 100); //需要指定非类型的函数模板参数的值
std::cout << hp << std::endl; //输出2000,因为最大值为2000
}
//可以在函数模板定义时,就指定函数模板参数
//非类型的函数模板参数
#include <iostream>
template<int max=2000, int min=1000, typename T> //模板定义时,直接指定非类型的函数模板参数的值
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 <iostream>
template<typename T,short count>
T 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 <iostream>
template <typename T>
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 //200
000B1996 6A 64 push 64h //100
000B1998 E8 48 F8 FF FF call ave<int> (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<short> (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 <iostream>
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 < count; i++)
{
bool bcase = Bigsort ? ary[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 <iostream>
template<typename T>
void Swap(T& a, T& b)
{
T tmp{ a };
a = b;
b = tmp;
}
template<typename T>
void Sort(T* ary, unsigned count, bool Bigsort = true)
{
for (T i = 1; i < count; i++)
for (T i = 1; i < count; i++)
{
bool bcase = Bigsort ? ary[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;
}