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);
}
当我用C++17编译时,一切都很好(如所需,没有断言)。使用C++20生成相同的代码会导致触发Assert。
在使用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&)
a_1 != a
计算为!((const A&)a_1 == a)
,这为您提供了不同的答案。
然而,您的操作符从根本上说是失败的。即使在C++17中,我们也有这样的场景:a_1 != a
计算为true
,而a != a_1
计算为false
。这基本上是试图像这样做动态相等的固有问题:this->equalTo(rhs)
和rhs.equalTo(*this)
实际上可能会做不同的事情。因此,这个问题与其说是C++20比较问题,不如说是一个基本的设计问题。
相关文章