C++17 运算符 ==() 和运算符!=() 代码在 C++20 中失败

Jac*_*own 2 c++ operator-overloading c++17 c++20

我有以下示例代码:

#include <assert.h>

struct Base
{
    bool operator==(const Base& rhs) const
    {
        return this->equalTo(rhs);
    }
    virtual bool equalTo(const Base& rhs) const = 0;
};
inline bool operator!=(const Base& lhs, const Base& rhs)
{
    return !(lhs == rhs);
}

struct A : public Base
{
    int value = 0;
    bool operator==(const A& rhs) const
    {
        return (value == rhs.value);
    }
    virtual bool equalTo(const Base& rhs) const
    {
        auto a = dynamic_cast<const A*>(&rhs);
        return (a != nullptr) ? *this == *a : false;
    }
};

class A_1 : public A
{
    virtual bool equalTo(const Base& rhs) const
    {
        auto a_1 = dynamic_cast<const A_1*>(&rhs);
        return (a_1 != nullptr) ? *this == *a_1 : false;
    }
};

int main()
{
    A_1 a_1;
    a_1.value = 1;

    // Make sure different types aren't equal
    A a;
    a.value = 1;
    assert(a_1 != a);
}
Run Code Online (Sandbox Code Playgroud)

当我使用 C++17 编译时,一切都很好(根据需要,没有断言)。使用 C++20 构建相同的代码会导致断言触发。

使用 C++20 编译时如何使现有代码正常工作?如果我使用 C++20 加大警告力度,我会得到'operator !=': unreferenced inline function has been removed;我怀疑这一切都与某种有关operator<=>()

这真的是从 C++17 到 C++20 的已知/期望的重大更改吗?

Bar*_*rry 10

在 C++17 中,该行

assert(a_1 != a);
Run Code Online (Sandbox Code Playgroud)

调用operator!=(const Base&, const Base&),因为当然,它是唯一的候选者。然后调用a_1->equalTo(a),它尝试向下转换a为 an A_1,这在你的逻辑中给你 false 。因此a_1 != a评估为true.


在 C++20 中,我们现在另外考虑根据==. 现在我们有三位候选人:

  1. Base::operator==(const Base&) const(重写)
  2. A::operator==(const A&) const(重写)
  3. bool operator!=(const Base&, const Base&)

其中,(2) 是最佳候选,因为它与两个参数更匹配。所以a_1 != a评估为!((const A&)a_1 == a),这会给你一个不同的答案。


然而,你的操作员从根本上被破坏了。即使在 C++17 中,我们也有这样的场景:a_1 != a评估为truewhilea != a_1评估为false。这基本上是尝试像这样进行动态平等的固有问题:this->equalTo(rhs)并且rhs.equalTo(*this)实际上可能会做不同的事情。因此,这个问题与其说是 C++20 比较问题,不如说是基本设计问题。