假设我们有以下实现:
这在
如果运算符的默认行为不合规,则默认行为是隐式删除该函数。因此,这里的默认行为有些不规范。
我唯一的假设是我们正在尝试在A的上下文中调用A::operator==(可能通过std::static_cast(*this) == b),这是非法的,因为该函数是受保护的而不是公共的。在上面的实现中,我们从B的上下文中调用了A::operator==,这是合法的。但我没有看到标准文件中明确指定这种特定行为的地方。
附录:这是上述“=default”实现的完整编译器转储:
class A {
protected:
bool operator==(const A&) const = default;
};
class B : public A {
public:
bool operator==(const B& b) const {
return A::operator==(b);
};
};
int main() {
B x, y;
x == y;
}
这在
gcc 12.1
和 clang 14.0
中可行。我还假设这是 B::operator==(const B& b)
的默认行为,因为标准规定如下:
所以我们只需要用一个类可以将 operator== 定义为默认值,返回值为 bool。这将生成每个基类和成员子对象的相等比较,按照它们的声明顺序。如果发现成员或基类在声明顺序中出现不相等,则测试将短路。如果这两个对象的基类和成员的值相等,则它们相等。
=default
替换上面的语句就可以了,对吗?其实并不完全是这样的...class A {
protected:
bool operator==(const A&) const = default;
};
class B : public A {
public:
bool operator==(const B& b) const = default;
};
int main() {
B x, y;
// Fails on both clang and gcc
// error: use of deleted function 'constexpr bool B::operator==(const B&) const'
// x == y;
x == y;
}
如果运算符的默认行为不合规,则默认行为是隐式删除该函数。因此,这里的默认行为有些不规范。
我唯一的假设是我们正在尝试在A的上下文中调用A::operator==(可能通过std::static_cast(*this) == b),这是非法的,因为该函数是受保护的而不是公共的。在上面的实现中,我们从B的上下文中调用了A::operator==,这是合法的。但我没有看到标准文件中明确指定这种特定行为的地方。
附录:这是上述“=default”实现的完整编译器转储:
<source>:8:10: note: 'constexpr bool B::operator==(const B&) const' is implicitly deleted because the default definition would be ill-formed:
8 | bool operator==(const B& b) const = default;
| ^~~~~~~~
<source>:8:10: error: 'bool A::operator==(const A&) const' is protected within this context
<source>:3:10: note: declared protected here
3 | bool operator==(const A&) const = default;
我预计有人会问 "为什么你要这样做?"。禁止基类执行 ==
操作,但允许派生类自愿执行 ==
操作的想法很常见,但使用自由函数 operator==(const B& lhs, const B& rhs)
的论点是有效的。这是目前的解决方法。