ISO C++ 说这些是模棱两可的,运算符重载

ISO C++ says these are ambiguous, operator overloading

当我在写一些关于基本运算符重载的代码时。我发现了这段代码,

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

这些都很好,直到我在 class

的声明之后添加它
MyInt operator+(const MyInt& lhs, const MyInt& rhs)
{
  MyInt copy = lhs;
  copy.data += rhs.data;

  return copy;
}

有了这个主要声明

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 {

从我看到的其他问题来看,都是错误而不是警告。所以我不太确定为什么它的代码仍然有效。希望有人能给我解释一下为什么会这样。

提前致谢。

From the other questions I've seen, they are all errors instead of warning.

这可能是因为守时的程序员告诉他们的编译器不要接受不符合标准的程序,您可能已经跳过了。例如,在使用 GNU 编译器时,他们会使用 -pedantic 甚至更严格的 -pedantic-errors 选项。

So I'm not really sure why does it code still work.

如果你不告诉你的编译器不接受非标准代码,那么如果他们支持它作为语言的扩展,它可能会接受它。在这种情况下,标准表示重载同样不明确并且程序格式错误,但编译器可能会乐观地猜测您可能打算使用的重载,而不管标准怎么说。

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

有一个成员函数 operator+(const MyInt&) const 可以这样调用:

MyInt m1;
MyInt m2;
m1 + m2;

还有一个免费函数operator+(const MyInt&, const MyInt&),可以这样调用:

MyInt m1;
MyInt m2;
m1 + m2;

这就是编译器抱怨的原因:语言定义说无法决定使用哪一个。任选其一。

通常的约定是只有free函数,通过调用operator+=.

来实现

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