为什么这个呼吁会员函数模棱两可

Why is this call to member function ambiguous?

本文关键字:函数 模棱两可 为什么      更新时间:2023-10-16

考虑此类:

class Base{
public:
    void func(double a) = delete;
    void func(int a) const {}
};
int main(){
    Base base;
    base.func(1);
    return 0;
}

使用clang 编译时,它会产生以下错误:

clang++ --std=c++11 test.cpp 
test.cpp:22:7: error: call to member function 'func' is ambiguous
    base.func(1);

使用G ,会产生警告:

g++ -std=c++11 test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:22:13: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: base.func(1);

为什么此代码模棱两可?

非静态成员函数,例如两个:

void func(double);    // #1
void func(int) const; // #2

还接受一个隐式对象参数,该参数在过载分辨率([Over.Match]/p1)中被视为任何其他参数:

超载分辨率是一种机制,可以选择给定表达式列表的最佳函数,这些函数是呼叫的参数和一组候选函数,可以根据呼叫的上下文调用。最佳函数的选择标准是参数数量,参数匹配候选函数的参数类型列表的很好,对象(对于非静态成员函数)对象匹配隐式对象参数以及候选功能的某些其他属性。

将隐式对象参数纳入成员函数签名后,编译器会看到两个过载:

void func(Base&, double);    // #1
void func(const Base&, int); // #2

并尝试根据呼叫选择最佳的可行函数:

Base base;
base.func(1);

baseBase类型的非const lvalue)转换为Base&的转换具有 ext excrack Match 等级(直接参考绑定产生身份转换) - - 请参见表13。但是,从baseconst Base&的转换也是 exceck ackect匹配等级,但是,[over.ics.rank]/p3.2.6声明#1具有更好的转换顺序:blockquote>

- s1和s2是参考绑定([dcl.init.ref]),并且参考引用的类型是相同的类型,除了顶级CV-Qualifiers,以及由该类型的类型以及由该类型的类型,该类型由该类型由该类型由此由此引用。S2引用比S1初始化的参考文献的类型更为CV质量。[示例

int f(const int &);
int f(int &);
int g(const int &);
int g(int);
int i;
int j = f(i);    // calls f(int &)
int k = g(i);    // ambiguous

现在,对于第二个参数,从积分prvalue 1double的转换为 floating-integral conversion ([cons.fpint]),该转换给了转换秩。另一方面, 1int身份转换,它是等级。对于此参数,#2被认为具有更好的转换序列([over.ics.rank]/3.2.2):

- S1的等级大于S2的等级,或S1和S2的等级相同,并且可以通过以下段落中的规则来区分,或者,如果不是这样,[...]

超载分辨率要成功,要求最多存在一个参数,转换序列有所不同([over.match.best]):

鉴于这些定义,如果对于所有参数i,ICS i (f1),可行函数f1被定义为比另一个可行函数f2更好的函数。sub> i (f2),然后

- 对于某个参数J,ICS J (F1)比ICS J (F2)更好的转换序列,或者,如果不是这样,[...]

在这里,ICS 0 (#1)优于ICS 0 (#2),但反过来,ICS 1 (#2)比ICS 1 (#1)更好,因此编译器无法在两个过载和检测歧义之间进行选择。

函数被超载时,超载分辨率首先进行。如果已删除的函数是最好的匹配并选择了程序。

因此,您的程序将产生与以下错误相同的错误,因为从int到double有隐式转换,并且编译器不知道您打算调用什么函数:

class Base{
public:
    void func(double a) {}
    void func(int a) const {}
};

它是因为func(int)中的const修饰符。base实例不是const。如果实例不是const,则C 编译器似乎首先找到non-const方法。然后,编译器发现该方法已被删除。因此编译器发出警告。

尝试删除const修饰符,或将const修饰符移至func(double)将摆脱警告。

看来此警告与隐式转换无关。即使您通过func((int)(1))调用func也不好。