我是否必须实现所有 4 个运算符重载才能处理所有 const 和非常量组合?

Should I have to implement all 4 operator overload in order to deal with all const and non-const combinations?

一般背景

我有一个自制的 struct,我想比较它的两个实例。为了做到这一点,我显然超载了 operator== 所以我将能够这样做。现在,可以使用 0 到 2 个 const 实例和 0 到 2 个非 const 实例调用此运算符。

因为我希望我的运算符 == 比较 2 个常量,因为它比较 constnon-const 的任何可能组合,对我来说最好的应该是只写一个重载可以处理所有可能的组合。但据我所知,我没有找到任何方法。

问题

这是否意味着如果我需要考虑所有可能的组合,我必须写出所有 4 种可能的重载?无论如何我可以避免只用 const 关键字更改编写 4 次相同的函数吗?


具体例子

所以这里是 struct。它表示计划中的一个对象,由其位置和与其关联的值组成:

struct Foo
{
    int x;
    int y;
    double value;
};

现在假设 2 Foo 相等,如果它们具有相同的值和相同的位置。我有以下运算符:

inline bool operator==(Foo object) // Compare two non-const Foo
{
    return (x == object.x) && (y == object.y) && (value == object.value);
}

但是,呃,不幸的是有些 Foo 可以是常量,这意味着我的对象不能按计划移动并且不能改变它们的值。现在我需要检查两个 const Foo 是否可以相等,以及非 const Foo 是否可以等于 const Foo

有没有办法做到这一点,但仍然避免编写与第一个函数几乎相同的以下函数?

inline bool operator==(const Foo &object) // Compare a non-const Foo with a const Foo
{
    return (x == object.x) && (y == object.y) && (value == object.value);
}

inline bool operator==(const Foo &object) const // Compare two const Foo
{
    return (x == object.x) && (y == object.y) && (value == object.value);
}

inline bool operator==(Foo object) const // Compare a const Foo with a non-const Foo
{
    return (x == object.x) && (y == object.y) && (value == object.value);
}

我对c++版本没有任何要求。它可以是 c++17 或 c++20。

如果你有一个非const Foo对象,你可以在需要const Foo&对象的地方使用它,你可以在它上面调用const方法,所以你应该只有一个重载:

bool operator==(Foo const& object) const {
    return (x == object.x) && (y == object.y) && (value == object.value);
}

对于行为不同的特定情况,您只需区分 const 和非 const 重载,具体取决于对象是 const 还是非 const ,例如 operator[]:

// You want to return a reference on non-const object and a const-reference
// on const object, so you need both overloads.
X& operator[](std::size_t);
const X& operator[](std::size) const;

您通常希望二元运算符具有非成员函数,必要时使用 friend。在您的情况下,由于所有成员都是 public,您可以简单地创建一个自由函数(在 struct 之外):

bool operator==(Foo const& lhs, Foo const& rhs) const {
    return lhs.x == rhs.x && lhs.y == rhs.y && lhs.value == rhs.vallue;
}

您也可以删除现在有点无关紧要的 inline 修饰符,例如,参见 When should I write the keyword 'inline' for a function/method?.

您还可以检查 What are the basic rules and idioms for operator overloading? 一些关于运算符重载的习语。

没有理由这样做!

只要只是比较,最好总是使用 const references:

  inline bool operator==(const Foo &object)const{
        return (x == object.x) && (y == object.y) && (value == object.value);
  }
  • 原因是您可以将 constnon-const 的地址或引用传递给 const 成员函数,而不是相反。

  • 根据 constness 事项,有时会发生重载。

与大多数二元运算符一样,运算符== 通常应作为单个非成员自由函数实现:

 inline bool operator==(const Foo & a, const Foo & b ) {
       return a.x == b.x && a.y == b.y && a.value == b.value;
 }