我有以下示例代码:
#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 中,我们现在额外考虑根据 ==
重写的候选者。所以现在我们有三个候选人:
Base::operator==(const Base&) const
(重写)A::operator==(const A&) const
(重写)bool operator!=(const Base&, const Base&)
其中,(2) 是最佳候选者,因为它更适合这两个参数。所以 a_1 != a
的计算结果为 !((const A&)a_1 == a)
,这会给你一个不同的答案。
但是,您的运算符(operator)根本就坏了。即使在 C++17 中,我们也有 a_1 != a
评估为 true
而 a != a_1
评估为 的情况错误
。这基本上是尝试像这样进行动态相等的固有问题:this->equalTo(rhs)
和 rhs.equalTo(*this)
实际上可能会做 不同的东西。所以这个问题与其说是 C++20 比较问题,不如说是基本设计问题。
关于C++17 operator==() 和 operator!=() 代码在 C++20 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69945406/