一个函数重载问题

srxumin 2016-05-08 12:15:18
《C++ primer》一书中并没有提到3个以上参数函数重载编译器会怎么选择的概念,我就自己在VS2015上做了试验,试验代码如下:
//程序1:
#include <iostream>
using std::cout;
using std::endl;

void ff(int a,float b,float c, float d)
{
cout << "f1" << endl;
}

void ff(double a, int b, double c, int d)
{
cout << "f2" << endl;
}

void main()
{
int i = 1, j = 2, k = 3, l = 4;
ff(i, j, k, l);
}

//程序2:
#include <iostream>
using std::cout;
using std::endl;

void ff(float a,int b,float c, float d) //程序1中的前两个参数调换了下顺序
{
cout << "f1" << endl;
}

void ff(double a, int b, double c, int d)
{
cout << "f2" << endl;
}

void main()
{
int i = 1, j = 2, k = 3, l = 4;
ff(i, j, k, l);
}

经实践表明:程序1的编译出现了二义性,程序2的编译选择了第二个函数执行,也就是签名为void ff(double a, int b, double c, int d)这个函数。
两个程序中的第一个ff函数都是1个精确匹配,3个提升。两个程序中的第二个ff函数都是2个精确匹配,2个提升,凭程直觉来说都两个程序都应该匹配第2个ff函数比较好,
问题1:程序1为什么会出现二义性错误,而程序2只是换了下参数的顺序又可以正常执行?
问题2:程序1匹配时为什么不考虑第4个参数,程序2在匹配时又考虑了第4个参数,这是为什么?
...全文
340 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
参考开源编译器源码是一个好方法,诸如GCC、 Free Pascal之类的...
赵4老师 2016-05-15
  • 打赏
  • 举报
回复
参考g++源代码相关片段。
  • 打赏
  • 举报
回复
可以明确地说,不存在double比float优先匹配int这种原则。 如果这种原则成立,那么ff(int, int, int, double)应该比ff(double, double, double, int)、ff(int, int, int, float)优先匹配,但是实际上这三个都有歧义,无法决定哪个优先。 确定重载函数匹配的原则是:如果不能找到精确匹配每一个参数类型(返回类型也作为参数同样考虑)的那个函数,忽略对应位置上的同种类参数,比较其余的参数类型,直到分出优劣,否则就出现歧义。 对于楼主的第一个程序,调用是ff(int, int, int, int),可用的重载 ff(int, float, float, float) ff(double, int, double, int) 比较之后是(*位置表示忽略): ff(int, float, *, float) ff(double, int, *, int) 这重情况是无法找出优先选择的(不存在double优先于float或者两个int优于一个int这种原则)。就出现了歧义。 而改成 ff(ifloat, int, float, float) ff(double, int, double, int) 比较之后是(*位置表示忽略): ff(*, *, *, float) ff(*, *, *, int) 当然会匹配第二个函数。
赵4老师 2016-05-13
  • 打赏
  • 举报
回复
  • 打赏
  • 举报
回复
引用 10 楼 akirya 的回复:
匹配优先类型转换 程序1 匹配,转换,转换,转换 转换匹配,转换,匹配 这样两个函数都有优先,不是匹配到某个函数优先就结束重载决议了,这样无法得到哪个更优先。 程序2 转换,匹配,转换,转换 转换,匹配,转换,匹配 第二个函数要么跟第一个函数一样的优先级,要么有优先。所以能够正确选择
手误更正下 不是匹配到某个参数优先就结束重载决议了
  • 打赏
  • 举报
回复
匹配优先类型转换 程序1 匹配,转换,转换,转换 转换匹配,转换,匹配 这样两个函数都有优先,不是匹配到某个函数优先就结束重载决议了,这样无法得到哪个更优先。 程序2 转换,匹配,转换,转换 转换,匹配,转换,匹配 第二个函数要么跟第一个函数一样的优先级,要么有优先。所以能够正确选择
paschen 版主 2016-05-13
  • 打赏
  • 举报
回复
引用 8 楼 srxumin 的回复:
[quote=引用 3 楼 lm_whales 的回复:] ...
即便是这样,下面的代码编译也是无法通过的,因为int到float和到double的转换等级都属于标准转换,它也不会优先匹配double呀,为什么出现4个参数就会选择double优先?
void fun(float f) {}
void fun(double d) {}

void main()
{
	int i;
	fun(i);//二义性错误
}
[/quote] 4个参数后者更加匹配吧,因为int 就像下面这两种情况会匹配到有int类型变量的那个函数:

void fun(float,int) {}
void fun(double,double) {}

void main()
{
	int i;
	fun(i,i);
}

void fun(float,float) {}
void fun(double,int) {}

void main()
{
	int i;
	fun(i,i);
}
srxumin 2016-05-13
  • 打赏
  • 举报
回复
引用 13 楼 DelphiGuy 的回复:
可以明确地说,不存在double比float优先匹配int这种原则。 如果这种原则成立,那么ff(int, int, int, double)应该比ff(double, double, double, int)、ff(int, int, int, float)优先匹配,但是实际上这三个都有歧义,无法决定哪个优先。 确定重载函数匹配的原则是:如果不能找到精确匹配每一个参数类型(返回类型也作为参数同样考虑)的那个函数,忽略对应位置上的同种类参数,比较其余的参数类型,直到分出优劣,否则就出现歧义。 对于楼主的第一个程序,调用是ff(int, int, int, int),可用的重载 ff(int, float, float, float) ff(double, int, double, int) 比较之后是(*位置表示忽略): ff(int, float, *, float) ff(double, int, *, int) 这重情况是无法找出优先选择的(不存在double优先于float或者两个int优于一个int这种原则)。就出现了歧义。 而改成 ff(ifloat, int, float, float) ff(double, int, double, int) 比较之后是(*位置表示忽略): ff(*, *, *, float) ff(*, *, *, int) 当然会匹配第二个函数。
大哥,看了一星期的跟贴,终于发现你这个说法最能说明我这个问题,感动啊!!!你这是从哪里得知的法则?好像知道的人很少啊,让我大开眼界了,牛!!!
srxumin 2016-05-13
  • 打赏
  • 举报
回复
引用 3 楼 lm_whales 的回复:
...
即便是这样,下面的代码编译也是无法通过的,因为int到float和到double的转换等级都属于标准转换,它也不会优先匹配double呀,为什么出现4个参数就会选择double优先?
void fun(float f) {}
void fun(double d) {}

void main()
{
	int i;
	fun(i);//二义性错误
}
lm_whales 2016-05-12
  • 打赏
  • 举报
回复
引用 6 楼 srxumin 的回复:
....
第一句话意思是说float的表示范围会小于int吗?这句话没看明白,能否解释一下?[/quote] float 不能精确表示全部int 因为二者位数一样多, 所以float的 尾数位数比int 全部位数 少很多 所以不能精确表示 全部int...有一一部分int,不能用 float精确表示
srxumin 2016-05-12
  • 打赏
  • 举报
回复
引用 3 楼 lm_whales 的回复:
int 精确表示范围超出了 float 因此,考虑精确表示的话,int 应该优先提升为 double 类型 程序2第二个函数,每个参数,都是优先于第一个函数的匹配顺序,因此可以确定,优先匹配第二个函数 程序1 第一个函数的第1个参数 int 显然比第二个函数 double 更有优先匹配权, 接着第二个函数的第2,3,4个参数,比第一个函数更有优先匹配权 这里出现了两种优先顺序,编译器不能决定哪个更好,于是出现模棱两可,也就是二义性了 。。。。。。。。。。。。。。。。。 当出现不能直接确定是否匹配的时候, 必须一一决定,只要不能确定优先级有差异,或者有二义性,就这么一路比较下去。 直到,能够完全匹配(对每个参数,所有重载函数中的一个函数能够比其他任何函数优先匹配), 或者产生二义性(两个函数交错优先匹配,或者两个函数所有参数匹配优先级相同), 结束匹配选择。
第一句话意思是说float的表示范围会小于int吗?这句话没看明白,能否解释一下?
lm_whales 2016-05-09
  • 打赏
  • 举报
回复
引用 4 楼 ri_aje 的回复:
重载解析会对比每一个参数,如果某个重载在每一个参数上都至少不比其他重载差,并且在至少一个参数上比其他重载好,则选择这个重载,否则就是无法决议,导致重载解析失败。拿着这个公式去过滤主楼的程序就能得到结论了。
++
ri_aje 2016-05-09
  • 打赏
  • 举报
回复
重载解析会对比每一个参数,如果某个重载在每一个参数上都至少不比其他重载差,并且在至少一个参数上比其他重载好,则选择这个重载,否则就是无法决议,导致重载解析失败。拿着这个公式去过滤主楼的程序就能得到结论了。
lm_whales 2016-05-09
  • 打赏
  • 举报
回复
int 精确表示范围超出了 float 因此,考虑精确表示的话,int 应该优先提升为 double 类型 程序2第二个函数,每个参数,都是优先于第一个函数的匹配顺序,因此可以确定,优先匹配第二个函数 程序1 第一个函数的第1个参数 int 显然比第二个函数 double 更有优先匹配权, 接着第二个函数的第2,3,4个参数,比第一个函数更有优先匹配权 这里出现了两种优先顺序,编译器不能决定哪个更好,于是出现模棱两可,也就是二义性了 。。。。。。。。。。。。。。。。。 当出现不能直接确定是否匹配的时候, 必须一一决定,只要不能确定优先级有差异,或者有二义性,就这么一路比较下去。 直到,能够完全匹配(对每个参数,所有重载函数中的一个函数能够比其他任何函数优先匹配), 或者产生二义性(两个函数交错优先匹配,或者两个函数所有参数匹配优先级相同), 结束匹配选择。
纹枰老妖 2016-05-08
  • 打赏
  • 举报
回复
参数入栈时的顺序是从右至左,也就是先入倒数第一的参数,然后看这个参数的默认类型,在您例子中是int,然后再比对一下程序中两个重载函数的参数列表最后一个参数,也就是那个【float d】和【int d】,结果程序发现第一个ff函数要做类型提升,而第二个ff函数正好是int型——相匹配【如果都不匹配,那就选择一个相对“较小”的提升】,于是程序就选择了第二个ff函数。换言之,如果最后的参数都不符合,而且都要做相同的提升转换,那么程序就只能接着比较倒数第二个参数了,以此类推。。。
paschen 版主 2016-05-08
  • 打赏
  • 举报
回复
int 会优先匹配double,不满足再匹配float吧(这里是我自己说的) 所以程序一两种函数都可以同时匹配到,而程序二会先匹配到double版本的

64,643

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧