C++17 operator==() 和 operator!=() 代码在 C++20 中失败

标签 c++ c++17 operator-overloading 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);
}

当我用 C++17 编译时,一切正常(没有断言,如所愿)。使用 C++20 构建相同的代码会触发断言

在使用 C++20 进行编译时,如何让现有代码正常工作?如果我使用 C++20 启动警告,我会得到 'operator !=': unreferenced inline function has been removed ;我怀疑这一切都与 operator<=>() 有关.

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

最佳答案

在 C++17 中,行

assert(a_1 != a);

调用 operator!=(const Base&, const Base&),因为它当然是唯一的候选者。然后调用 a_1->equalTo(a),它会尝试将 a 向下转换为 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),这会给你一个不同的答案。


但是,您的运算符(operator)根本就坏了。即使在 C++17 中,我们也有 a_1 != a 评估为 truea != a_1 评估为 的情况错误。这基本上是尝试像这样进行动态相等的固有问题:this->equalTo(rhs)rhs.equalTo(*this) 实际上可能会做 不同的东西。所以这个问题与其说是 C++20 比较问题,不如说是基本设计问题。

关于C++17 operator==() 和 operator!=() 代码在 C++20 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69945406/

相关文章:

c++ - 如何将 NULL 放入矩阵 vector 的所有单元格中?

c++ - 类模板特化推导是否应该考虑推导指导参数初始化?

C++ "forgetting"该变量在用作函数参数时是 constexpr

c++ 写运算符>,我似乎不正确地接近比较,我该如何正确地做到这一点?

c++ - VerQueryValueA 在资源 block 外写入无效内存

c++ - 实现自定义 Postgres 索引作为扩展

c++ - 绑定(bind)到 OpenGL 3.x VBO

c++ - 在 C++17 中没有从 std::string 到 std::string_view 的隐式转换(在 std::experimental::basic_string_view 中)

c# - 运算符重载

c++ - 创建自己的owner_ptr类;传递堆栈或静态分配地址时如何避免UB?