2017-03-03 27 views
10

考虑这个类:为什么这个对成员函数的调用模糊不清?

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

int main(){ 
    Base base; 

    base.func(1); 
    return 0; 
} 

当使用铛++,它产生以下错误编译:

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

随着克++,生成一个警告:

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

这是为什么代码暧昧吗?

+0

整数可以很容易地转换为浮点类型。虽然'func(int)'是最好的匹配,'func(double)'仍然是一个可行的选择,使得这个调用不明确。 –

+2

您似乎遇到了一些涉及const和非const成员函数的棘手逻辑。 FWIW,将'func(double)'改为'const'成员函数可以消除这个问题。 –

回答

10

非静态成员函数,像两:

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

也接受其在过载分辨率([over.match]/p1)的任何其他参数视为implicit object parameter

Overload resolution is a mechanism for selecting the best function to call given a list of expressions that are to be the arguments of the call and a set of candidate functions that can be called based on the context of the call. The selection criteria for the best function are the number of arguments, how well the arguments match the parameter-type-list of the candidate function, how well (for non-static member functions) the object matches the implicit object parameter, and certain other properties of the candidate function.

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

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

,并尝试选择基于所述呼叫的最佳可行函数:

Base base; 
base.func(1); 

base的转化率(其为Base类型的非const左值),以Base&具有精确匹配秩(直接参考结合产生Identity conversion) - 见Table 13。从baseconst Base&的转化也是精确匹配排名,然而,[over.ics.rank]/p3.2.6声明#1有一个更好的转换序列:

— S1 and S2 are reference bindings ([dcl.init.ref]), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers. [ Example:

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

— the rank of S1 is better than the rank of S2, or S1 and S2 have the same rank and are distinguishable by the rules in the paragraph below, or, if not that, [...]

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

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that, [...]

这里,ICS (#1)是比ICS更好(#2),但反过来,ICS (#2)是比ICS更好(#1),因此编译器无法在两次重载之间进行选择并检测出模糊性。

+0

我只是想发表类似的答案。一个区别:你为什么要写'Base *'? 13.3.1.4表示隐含的对象参数是“左值引用cv X”,所以'Base&'。 –

+0

优秀的答案。只是一点点的挑剔:'const base&'也直接绑定到'base'类型的参数,所以相应的隐式转换序列也是一个标识转换;没有资格转换。只是你所引用的子弹条件得到了满足,这使得其他转换(对'base&')更好。 – bogdan

+0

@bogdan我不确定这个部分,所以非常感谢。 –

0

当函数被重载时,首先发生重载解析。如果删除的功能是最佳匹配并且被选中,则该程序不合格。

因此,你的程序会产生相同的错误以下,因为从int隐式转换将翻一番,编译器不知道什么功能,你打算叫:

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

你的解释是缺乏的:是的有一个隐式转换'int'->'double',但是'int'完全匹配这个参数。最后一个关键在于'const' – bolov

-1

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

尝试删除const修改器,或将const修改器移动到func(double)将消除警告。

看来,这个警告不是关于隐式转换。即使你调用funcfunc((int)(1))也不好。

+1

你错了。它首先找不到第一种方法。两者不明确。 – bolov

相关问题