2016-02-02 32 views
1

当我在写关于基本运算符重载一些代码。我来到这个代码片段,ISO C++说,这些都是不明确的,操作符重载

struct MyInt { 
    public: 
    MyInt() : data() { }; 

    MyInt(int val) : data(val) { } 

    MyInt& operator++() { 
     ++data; 

     return (*this); 
    } 

    MyInt operator++(int) { 
     MyInt copy = *this; 
     ++data; 

     return copy; 
    } 

    MyInt& operator+=(const MyInt& rhs) { 
     data += rhs.data; 
     return *this; 
    } 

    MyInt operator+(const MyInt& rhs) const { 
     MyInt copy = *this; 
     copy += rhs; 

     return copy; 
    } 

    int data; 
}; 

这些都是正常,直到我的类

MyInt operator+(const MyInt& lhs, const MyInt& rhs) 
{ 
    MyInt copy = lhs; 
    copy.data += rhs.data; 

    return copy; 
} 

的声明之后加入这个权利有了这个主declartion

int main() { 
    MyInt mi = 10; 
    MyInt mi2 = 11; 
    MyInt mi3 = mi++ + ++mi2; 

    mi3 += mi2; 
} 

当我尝试编制,G ++我

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: 
    MyInt mi3 = mi++ + ++mi2; 
         ^
note: candidate 1: MyInt operator+(const MyInt&, const MyInt&) 
MyInt operator+(const MyInt& lhs, const MyInt& rhs) 
    ^
note: candidate 2: MyInt MyInt::operator+(const MyInt&) const 
    MyInt operator+(const MyInt& rhs) const { 
抛出此警告

从我见过的其他问题来看,它们都是错误而不是警告。所以我不确定为什么它的代码仍然有效。希望有人能向我解释为什么会发生这种情况。

在此先感谢。

+4

@Drop这是什么UB? 'MyInt mi3 = mi ++ + ++ mi2;'是三个不同的变量,所以没有UB。 – NathanOliver

+0

这里没有真正的问题。 “他们为什么不明确?” “为什么g ++将此作为警告并仍然创建二进制文件?” –

+0

@NathanOliver我认为这是因为左边的后缀意味着'const&'被转换为一个临时值......但这似乎排除了lhs + rhs定义是一个合格的重载,所以我'我不确定除了“ISO是这么说的”之外,还有什么是“模棱两可的”。 [另外,我上面的评论回复了一个现在被删除的评论,称这是一个值得采访的UB例子] –

回答

7

有一个成员函数operator+(const MyInt&) const可称为是这样的:

MyInt m1; 
MyInt m2; 
m1 + m2; 

还有一个免费的功能operator+(const MyInt&, const MyInt&),可称为是这样的:

MyInt m1; 
MyInt m2; 
m1 + m2; 

这就是为什么编译器抱怨:语言定义说,没有办法决定使用哪一个。挑一个或另一个。

通常的惯例是只自由的功能,并通过调用operator+=实现它。

该警告是告诉你,接受该代码是gcc的一个扩展。形式上,编译器不需要拒绝编译错误的代码。唯一的要求是他们发布了一个gcc做的诊断。完成之后,可以继续以某种编译器认为合理的方式编译代码。依赖这种扩展的代码是不可移植的。

+0

你碰巧知道在这种情况下g ++选择调用哪个超载?我可以看到两者的论点。 –

+0

根据user2079303的答案添加-pedantic后,它会变成错误,而不是由于模糊的重载。谢谢你详细解释这个问题! – Colorfusion

+0

@MarkB - 我不知道,但是从编译器的消息中,我猜测它是自由函数,因为那是“第一个最糟糕的转换比第二个最糟糕的转换更好”的那个。 –

2

从我看到的其他问题来看,它们都是错误而不是警告。

这可能是因为准时的程序员告诉他们的编译器不接受非标准的兼容程序,这些程序可能会跳过。例如,他们会使用GNU编译器时使用-pedantic或更严格-pedantic-errors选项。

所以,我真的不知道为什么它的代码仍然可以工作。

如果你不告诉你的编译器不接受非标准的代码,那么它可能会接受它,如果他们支持它作为语言的扩展。在这种情况下,标准说重载同样不明确,程序不合格,但编译器可能会比较乐观,并猜测你可能打算使用的重载,尽管该标准说了什么。

您显示的代码恰好在不使用任何选项的情况下编译时仅使用g ++中的警告,但使用-pedantic选项时,这些警告将成为错误。通常-pedantic只会在使用语言扩展时添加警告,但在这种情况下,它似乎会将警告提示为错误。

+0

添加迂腐之后,由于含糊不清的超载,它变成了你所说的错误,现在对我来说是有意义的。感谢您的帮助! – Colorfusion