函数重载和函数模板

c语言中函数名字不可重复,但是可以写代码实现

普通的函数重载

这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同和返回值没有关系(因为就像我想调用Add(1,2),Add重载的几个函数仅仅返回值不同,编辑器就不知道去找哪一个,就有歧义了)

情况1-数组

int ave(int*pa,int count)int ave(int pa[],int count);不可重载

情况2-引用

int ave(int &a,int &b);int ave(int a,int b);

编译时候不报错

但是ave(100,200);运行不报错,因为不可以用常量初始化引用

int a=100,b=200;
ave(a,b); //运行时候报错,因为有歧义,不知道走哪个函数

情况三-强制类型转换

float ave(float a,float b);
int ave(int a,int b);
float a=1.0f,b=2.0f;
ave((int)a,(int)b); //依然是走float,因为强制类型转换后的变量是临时变量,无固定的内存地址,则搞不了引用

情况4-const常量

int ave(int a,int b);
int ave(const int a,const int b);

不可重载,属于函数的const 常量,形同虚设了,编辑器还是会歧义

情况5-const常量引用

int ave(int &a,int &b);
int ave(const int &a,const int &b);

不会歧义,因为第二个函数需要两个const常量来初始化

情况6-函数默认参数

int ave(int a=1,int b=2);
float ave(float a=1.0f,float b=2.0f);

不行,编辑器又歧义了

函数模板(c++专属)

#include<iostream>
using namespace std;

template<typename type1>
type1 ave(type1 a, type1 b)
{
	type1 x = a;
	return (a + b + x) / 3;
}
int main() {
	cout << ave(1, 2) << endl;
	cout << ave(1.4, 1.6) << endl;
	return 0;
}
也可以搞成指针

type1 *a

c = *ave(&a,&b,&c);
也可以强制指定
cout << ave<float>(1.4, 1) << endl; //参数部分会涉及强制类型转换

址传递的困惑

正常值传递

#include<iostream>
using namespace std;
template<typename type1>
void swap(type1* a, type1* b)
{
	type1 temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
int main() {
	int a = 1, b = 3;
	swap(&a,&b);
	cout << a << " " << b << endl;
	return 0;
}

但是这样就失去了模板的意义,就只能搞指针

#include<iostream>
using namespace std;
template<typename type1>
void swap(type1 a, type1 b)
{
	type1 temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
int main() {
	int a = 1, b = 3;
	swap(&a,&b);
	cout << a << " " << b << endl;
	return 0;
}

我们很多人会以为是这样写,但是这样的话模板就分不清楚,到底是引用还是指针,而且还报错了

编译器默认成引用了

对于这样有歧义的情况,我们也有对策-可以单独列出例外情况,因为函数重载优先级大于函数模板

但是要是把哪个重载的函数改为void返回值,编译器会报错,要和前面模板一个形式

也可以解决这个问题

所以在处理函数模板例外情况时候,不加template<>限制会更加灵活

函数模板进阶

带三个参数的函数模板

情况一:就强制指定第一个(一般写返回值),然后将参数类型交给编辑器去猜
#include<iostream>
using namespace std;

template<typename TR,typename T1,typename T2>
TR ave(T1 a, T2 b) {
	return (a + b) / 2;
}

int main() {
	ave<double>(10, 10.3f);
	return 0;
}
情况二:直接在模板函数的形参列表里面强制指定
#include<iostream>
using namespace std;

template<typename TR,typename T1,typename T2>
TR ave(T1 a, T2 b,int c) {
	return (a + b) / 2;
}

int main() {
	ave<double>(10, 10.3f,30);
	return 0;
}

T1之类的就当正常数据类型来用,可以搞指针,可以搞默认参数

decltype和auto的补充知识

#include<iostream>
using namespace std;

template<typename T1, typename T2>
decltype(auto) bigger(T1 &a, T2 &b) { /*decltype默认以return后面的表达式来推断类型,如果不想这样,还是要原始方式结尾*/
	return a < b ? a : b;
} //加了decltype就是引用类型了,不加就不是

int main() {
	int a = 50;
	int b = 50000000;
	bigger(b, a) = -250;
	cout << b << endl;
	return 0;
}

上面代码可以把b改为-250,因为bigger是引用类型

这段代码的反汇编

将a的地址放到eax中,然后后面将-250的补码移到a的位置

去掉decltype这样是报错的,因为就像2500 = -250,右值是不能赋值的

上面这样操作也行,但是因为a,b不是引用所以没有改变全局变量a,b的值,改的是局部变量b的值

对于这个代码的反汇编

先将a的值移到eax中,将-250的补码移到eax寄存器中

一个困惑了很多人的问题(大部分书上没有解决这个问题)
#include<iostream>
using namespace std;

template<typename T1, typename T2>
decltype(auto) bigger(T1 &a, T2 &b) { 
	return a < b ? a : b;
}

int main() {
	float a = 50;
	int b = 50000000;
	bigger(b, a);
	cout << b << endl;
	return 0;
}

这个bigger的类型是float还是float&(中间存在强制类型转换,强制类型转换生成的是临时变量),float类型

不能引用强制类型转换的量,因为没有固定内存地址,是右值

改成a都不行

函数模板参数进阶

模板默认参数

非类型的模板参数

使用非类型参数处理固定大小的数组

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值