我试图理解下面代码中的模糊调用,但我无法理解。其中三个给予了一个错误。
struct A {
virtual void func(int a, float b) const { std::cout << "a1" << std::endl; }
virtual void func(double a, float b) { std::cout << "a2" << std::endl; }
void func(unsigned int a, char b) { std::cout << "a3" << std::endl; }
};
int main() {
A baseObj;
baseObj.func(1, 1.0);//Error : expecting a1
baseObj.func(2, 2.0f);//Error : expecting a1
baseObj.func(3, 'c');//Error : expecting a3
return 0;
}
字符串
如果我把它改成:
baseObj.func(1.0, 1.0);//a2
baseObj.func(2.0, 2.0f);//a2
baseObj.func(3, 'c');//Error, if i remove unsigned from function, then it gives a3.
// I dont know what exactly happening here
型
有人能解释一下如何找出模棱两可的呼叫吗?
谢了
1条答案
按热度按时间plicqrtu1#
正如有人在现已删除的答案中指出的那样,MSVC有一个最雄辩的解释:
字符串
您可以在此处亲自查看:https://godbolt.org/z/ee4E61d79
为什么会这样?
在第一个调用中,您传递了一个
int
(1
)和一个double
(1.0
),并期望调用a1
。但是,a1
需要一个常量对象(由于const
限定符)、一个int
和一个float
。因此,必须进行两种转换:必须将
baseObj
从A
“转换”为const A
,并且必须将1.0
从double
转换为float
。同样,a2
需要两次转换--1
到double
和1.0
到float
。与a3
相同--1
到unsigned int
以及1.0
到char
.在编译器看来,所有3个候选项都是等效的,因为它们都需要转换。因此,它不知道应该调用哪一个,并给出错误。
类似的事情发生在第二次和第三次呼叫中。
更新以回应评论。
重载排序是over.ics.rank中介绍的一个相当复杂的过程。为了使我的回答简单--并希望没有人会注意到;),我把事情简单化了。
但是,不用花几个小时去钻研标准,就我所知,正在发生的事情是这样的:
第4节指出,转换序列按其秩排序。在第三次呼叫中,所有3个候选人都具有相同的等级--转换,因为他们都需要转换。
注意:
int
->unsigned int
是转换,而不是促销。第3.2节定义了何时一个转换序列优于另一个。并且无论转换的次数如何,相同秩的序列都被认为是不可区分的(两者都不是更好的)。
所以,这就是为什么第三次(以及前两次)调用失败的原因。