【问题标题】:C++20 comparison: warning about ambiguous reversed operatorC++20 比较:关于模棱两可的反向运算符的警告
【发布时间】:2020-06-08 17:24:07
【问题描述】:

考虑这个有效的 C++17 示例:

struct A {
   bool operator==(const A&);
};


int main() {
   return A{} == A{};
}

compiled in clang with -std=c++20 it gives:

<source>:7:15: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'A' and 'A') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]

   return A{} == A{};

          ~~~ ^  ~~~

<source>:2:9: note: ambiguity is between a regular call to this operator and a call with the argument order reversed

   bool operator==(const A&);

这个警告是否意味着 C++20 不允许使用典型的比较运算符来比较两个相同类型的对象?什么是正确的选择?这种情况在未来的草稿中是否会发生变化?

【问题讨论】:

  • 我将把细节留给语言律师,但创建函数const 应该会让警告消失。我认为警告存在,因为您临时调用 operator==
  • @aep 添加const 确实会消除警告,但删除临时(A a, b; a == b)不会。谢谢,我想它一定与== 的一侧是 const 而不是另一侧有关。
  • C++20 没有更多的变化(除了那些仍在上次会议上为该版本合并的变化)。
  • 我发誓,我喜欢关注 "use non-member overloads" guideline 的一半原因是很容易忘记声明成员函数本身 const,非成员函数只需要记住声明参数const.

标签: c++ c++20


【解决方案1】:

此警告是否意味着 C++20 不允许使用典型的比较运算符来比较相同类型的两个对象?什么是正确的选择?这种情况在未来的草稿中是否会发生变化?

这实际上不是一个典型的比较运算符,它已经有点错误了 - 因为它只允许在一侧有一个 const 对象(你的类型 A 也不会满足新的 equality_comparable 概念,甚至没有任何语言变化)。

你必须这样写:

struct A {
   bool operator==(const A&) const;
//                          ^^^^^^
};

这是 C++20 的最终规则。


具体问题是,在 C++20 中,比较运算符添加了重写和反转候选的新概念。因此,查找表达式a == b 最终也会匹配b == a 等运算符。在典型情况下,这意味着您必须编写更少的运算符,因为我们知道相等是可交换的。

但如果你有一个 const 不匹配,你最终会得到这两个候选者:

bool operator==(/* this*/ A&, A const&); // member function
bool operator==(A const&, /* this*/ A&); // reversed member function

带有两个A 类型的参数。第一个候选人在第一个论点中更好,第二个候选人在第二个论点中更好。没有一个候选人比另一个更好,因此模棱两可。

【讨论】:

    【解决方案2】:

    重载决议的一般规则是,每个参数类型必须单独至少与所选函数的参数类型一样接近任何其他函数的参数类型:

    struct A {A(int);};
    void f(long,int);   // #1
    void f(int,A);      // #2
    void g() {f(0,0);}  // error: ambiguous
    

    #2 的第二个参数的更糟糕的转换并不能弥补第一个参数的intlong 转换。

    在 C++20 中,添加了各种重写规则,以避免编写如此多几乎相同的比较运算符重载。虽然手写的“反转候选”和相同的编译器生成的之间微不足道的歧义由 tie-breaker 规则处理,这些规则更喜欢真正的函数,但这(再次)不足以弥补更糟糕的转换对于任何论点。

    根据公认的 (C++17) 实践仔细编写的比较运算符很少会与此发生冲突,但是像这样的 可疑 签名(带有非对称 const)很可能会出现问题(以新的方式)。希望发现的错误比此扩展引起的错误更多。

    【讨论】:

    • @Barry:嗯,(Clang)将其降级为警告为人们提供了另一种“缓慢”转换的方式(-Wno-error=ambiguous-reversed-operator 除了某种前瞻性的 C++17 模式)。
    猜你喜欢
    • 1970-01-01
    • 2013-11-18
    • 2023-03-13
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    相关资源
    最近更新 更多