为什么这个成员函数的调用含糊不清?

时间:2017-03-03 08:14:10

标签: c++ c++11 language-lawyer

考虑这个课程:

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);

为什么这段代码含糊不清?

3 个答案:

答案 0 :(得分:13)

非静态成员函数,如两者:

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

还接受一个implicit object parameter,它在重载决议([over.match]/p1)中被视为任何其他参数:

  

重载解析是一种机制,用于在给定作为调用参数的表达式列表和可根据调用上下文调用的一组候选函数的情况下选择要调用的最佳函数。最佳函数的选择标准是参数的数量,参数与候选函数的参数类型列表的匹配程度,对象与隐式对象参数的匹配程度如何(对于非静态成员函数)< / strong>,以及候选函数的某些其他属性。

将隐式对象参数合并到成员函数签名中后,编译器会看到两个重载:

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

并尝试根据调用选择最佳可行功能:

Base base;
base.func(1);

base(类型Base的非常数左值)到Base&的转换具有完全匹配排名(直接参考绑定收益率) Identity conversion) - 请参阅Table 13。从baseconst Base&的转换也是完全匹配排名,但是,[over.ics.rank]/p3.2.6声明#1有更好的转换顺序:< / p>

  

- S1和S2是引用绑定([dcl.init.ref]),引用引用的类型除了顶级cv限定符之外是相同类型,并且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的转换是浮动积分转换[conv.fpint]转换排名。另一方面,1int身份转换,它具有完全匹配等级。对于此参数,#2被认为具有更好的转换序列([over.ics.rank]/p3.2.2):

  

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

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

  

鉴于这些定义,如果对于所有参数i,可行函数F1被定义为比另一个可行函数F2更好的函数,ICS i (F1)不是比ICS更差的转换序列< sub> i (F2),然后

     

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

这里,ICS 0 (#1)优于ICS 0 (#2),但反过来,ICS 1 (# 2)优于ICS 1 (#1),因此编译器无法在两个重载之间进行选择并检测模糊性。

答案 1 :(得分:0)

当函数重载时,首先会发生重载决策。如果删除的功能是最佳匹配并且被选中,则程序格式错误。

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

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

答案 2 :(得分:-1)

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

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

似乎此警告与隐式转换无关。即使您按func调用func((int)(1))也不好。