Nivlem
Nivlem

Reputation: 493

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

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.

Upvotes: 1

Views: 217

Answers (3)

Holt
Holt

Reputation: 37616

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.

Upvotes: 1

user2100815
user2100815

Reputation:

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

Upvotes: 2

Maestro
Maestro

Reputation: 2552

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.

Upvotes: 1

Related Questions