3

What is the proper/canonical way of overloading binary relational operators in C++?

Is it better to use member functions, or friend free functions?

E.g.:

class X {
 public:
  ...

  // Use member function overloads
  bool operator==(const X& rhs) const { 
    return m_text == rhs.m_text; 
  }

 private:
  std::string m_text;
};

or:

class X {
 public:
  ...

  // Use friend free function overloads
  friend bool operator==(const X& lhs, const X& rhs) { 
    return lhs.m_text == rhs.m_text; 
  }

 private:
  std::string m_text;
};
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • [This question](http://stackoverflow.com/questions/1691007/whats-the-right-way-to-overload-operator-for-a-class-hierarchy?rq=1) might help maybe. – Rakete1111 Nov 10 '16 at 18:08

2 Answers2

4

It doesn't make much difference, except that

  • an instance of X needs to be on the left-hand-side of the equality operator for the member version to work. If you ever want to write

    X x("hello");
    string s("hello");
    assert(s == x);
    

    you need a non-member.

  • if you're implementing all the binary relational operators, that's a potentially large increase in your class's surface area.

    I'd generally prefer this kind of auxiliary interface to be kept apart from the main class logic where possible (unless, of course, your class's primary concern is comparison).

    Using non-friend free operators and a minimal public interface is perhaps even better.

Useless
  • 64,155
  • 6
  • 88
  • 132
3

The one thing you should be aware of are implicit conversions.

If your class supports implicit conversions from other types, it may be useful to make operator== a friend to support implicit conversions on its first arguments.

In other cases I suppose that it is more the matter of style.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • Correct me if I'm wrong, but implicit conversions take place even with member operators. – Bruno Ferreira Nov 10 '16 at 18:12
  • 1
    @BrunoFerreira basically, parameters are eligible for implicit conversions only if they are listed in the parameters list, but when *operator==* is a member function the first parameter is *this* and it is not eligible for implicit conversion. – Edgar Rokjān Nov 10 '16 at 18:20
  • Sure. [I made a small test case](http://coliru.stacked-crooked.com/a/5eefd0778684b48e) and yes, if i remove the implicit conversion to int it fails. – Bruno Ferreira Nov 10 '16 at 19:17
  • Giving it a better thought, member functions are `__thiscall`, meaning that it has an implicit `this` as first parameter. In my test case, it should be something like `bool operator==(A* this, int x)`. By C++ standard, the first argument is the left side and the second, the right side. – Bruno Ferreira Nov 10 '16 at 19:20