Reputation: 3138
Let's say I have a class called Person
and another class called School
. In the second class I have a private field which is a set (of the standard library). The set represents the students (objects of the first class). In one of the functions of School
, I want to check if a studet does not exist in the set of students. For that I do:
if (students.find(student) == students.end()) {
// throw exception
}
I was wondering if I need to overload one of the comparison operators of Person
because otherwise how find
knows to compare the objects? Reading the docs I see that this method is only using operator<
. Does it mean that I have to overload it in Person
? If I don't overload it, does it use a default one? Does the compiler creates a default operator less? Otherwise, as I understand, it should fail building?
Upvotes: 1
Views: 400
Reputation: 6131
Overloading the "less than" operator for a type is an option, but not necessarily the only way.
When you create a std::set
, you can provide a comparator to compare objects. By default, the comparator it uses is std::less
, which will use operator<
, but your comparator can do anything else, provided it meets the requirements of ordering properly.
Some examples:
#include <set>
#include <functional>
struct EvenOddIncreasing {
bool operator()(int a, int b) const noexcept {
if ((a&1) < (b&1)) return true;
if ((a&1) > (b&1)) return false;
return a < b;
}
};
std::set<int, EvenOddIncreasing> evenOddIncreasing{1,2,3,4,5};
std::set<int, std::greater<>> decreasing{1,2,3,4,5};
std::set<int, std::less<>> increasing{1,2,3,4,5};
The code above uses an int
, which has operator<
obviously defined for it, but since the std::set
is passed explicit comparator types, it will use those for ordering. Note, evenOddIncreasing
is an example of a custom comparator that puts evens first, then odds, and in increasing order.
The above sets will have the following orderings:
even odd increasing...2 4 1 3 5
decreasing...5 4 3 2 1
increasing...1 2 3 4 5
In C++20, you could even use a lambda, but not with older versions of C++.
See it live:
https://godbolt.org/z/9ExhEGbb6
Upvotes: 1
Reputation: 1017
1.: Actually overloading operator<
is just 1 way the other way is to define a functor and give it to the set eg.:
class Comper_functor{
bool operator()(const Person& a, const Person& b);
}
...
std::set<Person,Comper_functor> s;
works just fine if you want to avoid overloading operator<
2.: operator<
(or the compere function) does not have to be a "logical" operator just a consistent one for std::set
. So it is good if for any Person a,b,c
a) if a<b
and b<c
-> a<c
b) if a<b
-> !b>a
c) if !a<b
and !b<a
-> a==b
The easiest way to make it work is compering the 2 person member by member.
Eg.: for a
class Ponit{
double x,y;
public:
bool operator<(const point& o)const{
if (x!=o.x) return x<o.x;
return y<o.y;
}
}
works fine. Even if a point is can't be "smaller" then an other one.
3.: in c++20 you can say in the class definition
std::weak_ordering operator<=>(const Person& o)const=default;
bool operator==(const Person& o)const=default;
To generate all operators <,>,<=,>=,==,!=
In older versions you have to define operator<
manually
Upvotes: 4