4
votes

I want to use my class as key in a map, so I overload operator+. It works well if I overload it as a friend function. When I overload it as a member function inside the class, it causes a compile error.

error C2678: binary '<': no operator found which takes a left-hand operand of type 'const Syl' (or there is no acceptable conversion)'.

In details, this doesn't compile, and generate the compile error:

Syl.h

bool operator< (const Syl& rhs);

Syl.cpp

bool Syl::operator< (const Syl& rhs) {  return false; }

While this compiles.

Syl.h

friend bool operator< (const Syl& lhs, const Syl& rhs);

Syl.cpp

bool operator< (const Syl& lhs, const Syl& rhs) {   return false; }

I don't know why. I know that operator< is binary, but is there anyway to overload it as function member?

2
Due to the way overload resolution and implicit conversions work, the friend version is a better idea anyway. - Sebastian Redl
The friendly version specifies, both operands as const the other version only says that the input parameter is const. You must mark the method as such... You have to read the error carefully, pay an extra attention to the meaning of words such as const, signed, etc. - Kupto

2 Answers

3
votes

Typically, member operators such as operator< do not modify the object they operate on. If that is the case you need to specify that the method is constant by putting the keyword const at the end of the declaration, i.e.

class Syl {
  ...
  public:
  bool operator<(const Syl& rhs) const;  
}

An operator like that can be used with STL containers such as std::map.


Your current version of the member operator, when translated into a stand-alone operator would look as:

friend bool operator<(Syl& lhs, const Syl& rhs);

Notice the lack of const for lhs. It is still correct per se, but atypical. You need to provide an l-value as lhs. If you provide something else you get the ``no operator found...'' error. STL std::map does not expect that either, hence your error, probably originating from standard headers, somewhere deep in the template implementation.

2
votes

Assuming a and b are both of type Syl, your first (member form) is not valid in an expression a < b if a is const, and will result in a compilation error.

To fix that, you need to specify the member operator<() as

bool operator< (const Syl& rhs) const;    // note the trailing const

Without that trailing const, in an expression a < b, a cannot be const (i.e. the operator<() is permitted to change it).

Your second form is correct, since it specifies that both operands are const references.

Comparison operators like < don't generally change EITHER of their operands. The const qualifiers communicate that fact.

Bear in mind that you can provide the member form OR the non-member form. Providing both will cause an error due to ambiguity (the compiler has no basis to prefer one over the other, when it sees an expression like a < b).