In C++ do you need to overload operator== in both directions?

Yes, you do. Just like in lots of other languages, C++ takes sides and comparisons between two objects of different types will lead to calls to two different comparison operators depending on the order.

Of course, you want them to be consistent and not surprising, so the second should be defined in terms of the first.


(C++20 onward)

With the acceptance of p1185 into C++20, you don't need to provide more than one overload. The paper made these changes (among others) to the standard:

[over.match.oper]

3.4 - [...] For the != operator ([expr.eq]), the rewritten candidates include all member, non-member, and built-in candidates for the operator == for which the rewritten expression (x == y) is well-formed when contextually converted to bool using that operator ==. For the equality operators, the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, for each member, non-member, and built-in candidate for the operator == for which the rewritten expression (y == x) is well-formed when contextually converted to bool using that operator ==. [ Note: A candidate synthesized from a member candidate has its implicit object parameter as the second parameter, thus implicit conversions are considered for the first, but not for the second, parameter. — end note ] [...]

8 [...] If a rewritten candidate is selected by overload resolution for a != operator, x != y is interpreted as (y == x) ? false : true if the selected candidate is a synthesized candidate with reversed order of parameters, or (x == y) ? false : true otherwise, using the selected rewritten operator== candidate. If a rewritten candidate is selected by overload resolution for an == operator, x == y is interpreted as (y == x) ? true : false using the selected rewritten operator== candidate.

The above means that not only do you not need to provide the operator with the order of the operands reversed, you also get != for free! Furthermore, the operator== function can be a member if it makes sense. Though as the note in the first paragraph above says, it being a member or free function will affect implicit conversions so you still need to bear that in mind.


(Upto C++17)

You do if you want to support comparisons where the string is on the left and the Foo is on the right. An implementation won't reorder the arguments to an overloaded operator== to make it work.

But you can avoid repeating the implementation's logic, though. Assuming your operator should behave as expected:

inline bool operator==(const std::string& objA, const Foo& objB) {
    return objB == objA; // Reuse previously defined operator
}