1

General context

I have a self-made struct and I want to compare two instance of it. In order to do that I obviously overload the operator== so I will be able to do so. Now, this operator may be called with 0 to 2 const instances and 0 to 2 non-const instances.

As I want my operator == to compare 2 const as it compare any possible combination of const and non-const, the best for me should be to write only one overload which can deal with all possible combination. But as far as I know, I didn't find any way to do so.

Question

Does that mean that if I need to consider all possible combination, I have to write all 4 possible overloads ? Is there anyway I can avoid to write 4 times the same function only with const keywords changing ?


Specific example

So here is the struct. It represents an object on a plan, and consists of its position and a value associated to it:

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

Now let's say 2 Foo are equal if they have the same value and the same position. I have the following operator:

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

But, eww, unlucky some Foo can be constants, meaning that my objects can't move on the plan and can't change their value. And now I need to check if two const Foo can be equals and if a non-const Foo can be equal to a const Foo.

Is there anyway I can do that but still avoid to write those following functions which are almost the same as the first one ?

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);
}

I don't have any requirements on c++ version. It can ever be c++17 or c++20.

DrosvarG
  • 483
  • 3
  • 14

3 Answers3

2

Operator==, like most binary operators, should normally be implemented as a single, non-member, free function:

 inline bool operator==(const Foo & a, const Foo & b ) {
       return a.x == b.x && a.y == b.y && a.value == b.value;
 }
  • Which c++ standard allow to do this ? Because I tried this too but it doesn't compile for me. I got a `too many parameters for binary operator 'operator=='` error – DrosvarG Aug 07 '19 at 12:13
  • 1
    C++ has always allowed (and encouraged) writting functions like this. As I said, you need to make it a non-member function. –  Aug 07 '19 at 12:17
1

If you have a non-const Foo object, you can use it where const Foo& object are expected, and you can call const-method on it, so you should only have one overload:

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

You only needs to differentiate const and non-const overloads for specific cases where the behavior is different depending if the object is const or non-const, e.g., for 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;

You usually want to have non-member functions for binary operators, with friend if necessary. In your case, since all members are public, you can simply create a free function (outside the struct):

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

You can also drop that inline modifier which is kind of irrelevant nowadays, see, e.g., When should I write the keyword 'inline' for a function/method?.

You can also check What are the basic rules and idioms for operator overloading? for some idioms regarding operator overloading.

Holt
  • 36,600
  • 7
  • 92
  • 139
  • Alright, I see. I started by writing the passing-by-value function and got misleaded by the error I got, so I just added the `const reference` one and assumed that I needed all of those I described. Thanks for the precisions on the utility of multiple overloads also – DrosvarG Aug 07 '19 at 12:12
1

There is no reason to do so!

As long as it is just comparison then it is preferred always to use const references:

  inline bool operator==(const Foo &object)const{
        return (x == object.x) && (y == object.y) && (value == object.value);
  }
  • The reason is you can pass the address or reference of const and non-const to a const member function but not the contrary.

  • There are some cases when overloading depending on constness matters.

Maestro
  • 2,512
  • 9
  • 24