理解C++中的二义性调用

rta7y2nd  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(86)

我试图理解下面代码中的模糊调用,但我无法理解。其中三个给予了一个错误。

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


有人能解释一下如何找出模棱两可的呼叫吗?
谢了

plicqrtu

plicqrtu1#

正如有人在现已删除的答案中指出的那样,MSVC有一个最雄辩的解释:

<source>(13): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or       'void A::func(double,float)'
<source>(5): note: or       'void A::func(int,float) const'
<source>(13): note: while trying to match the argument list '(int, double)'
<source>(14): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or       'void A::func(double,float)'
<source>(5): note: or       'void A::func(int,float) const'
<source>(14): note: while trying to match the argument list '(int, float)'
<source>(14): note: note: qualification adjustment (const/volatile) may be causing the ambiguity
<source>(15): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or       'void A::func(double,float)'
<source>(5): note: or       'void A::func(int,float) const'
<source>(15): note: while trying to match the argument list '(int, char)'

字符串
您可以在此处亲自查看:https://godbolt.org/z/ee4E61d79
为什么会这样?
在第一个调用中,您传递了一个int1)和一个double1.0),并期望调用a1。但是,a1需要一个常量对象(由于const限定符)、一个int和一个float
因此,必须进行两种转换:必须将baseObjA“转换”为const A,并且必须将1.0double转换为float。同样,a2需要两次转换--1double1.0float。与a3相同--1unsigned int以及1.0char.
在编译器看来,所有3个候选项都是等效的,因为它们都需要转换。因此,它不知道应该调用哪一个,并给出错误。
类似的事情发生在第二次和第三次呼叫中。
更新以回应评论。
重载排序是over.ics.rank中介绍的一个相当复杂的过程。为了使我的回答简单--并希望没有人会注意到;),我把事情简单化了。
但是,不用花几个小时去钻研标准,就我所知,正在发生的事情是这样的:
第4节指出,转换序列按其秩排序。在第三次呼叫中,所有3个候选人都具有相同的等级--转换,因为他们都需要转换。
注意:int-> unsigned int是转换,而不是促销。
第3.2节定义了何时一个转换序列优于另一个。并且无论转换的次数如何,相同秩的序列都被认为是不可区分的(两者都不是更好的)。
所以,这就是为什么第三次(以及前两次)调用失败的原因。

相关问题