Defining an Operator
GOALWrite `operator<` so `sort` can order your own type.
This is the lesson in this unit that actually pays off. sort has to know which of two items comes first. Instead of a separate comparator, define operator< inside the type and sort, set and priority_queue all just work.
ON THIS PAGE
//THE EXAMPLE
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
struct Student {
string name;
int score;
bool operator<(const Student& other) const {
return score > other.score;
}
};
int main() {
vector<Student> v = {{"Bat", 70}, {"Suvd", 95}, {"Tuul", 82}};
sort(v.begin(), v.end());
for (const Student& s : v) {
cout << s.name << " " << s.score << endl;
}
return 0;
}Suvd 95 Tuul 82 Bat 70
//LINE BY LINE
Watch it run
Three students, in the order they were written.
Which operators are worth defining
Defining operators is powerful but easy to overdo — it can make code harder to read, not easier. In contests one of them does nearly all the work.
| Operator | When it earns its place |
|---|---|
< | sort, set, priority_queue — байнга / constantly |
== | Хайлт, харьцуулалт / searching and comparing |
+ | Тоо шиг зүйл (вектор, матриц) / things that behave like numbers |
<< | Хэвлэх — тэмцээнд ховор / printing — rarely worth it in a contest |
< must give a STRICT ordering: equal items have to give false. Writing <= can send sort off the end of the array and crash, with no compiler warning.
Sorting without writing one
If you need a different order in just one place, do not define an operator. Hand the sort a comparison instead — then one type can be sorted several ways.
sort(v.begin(), v.end(), [](const Student& a, const Student& b) {
return a.name < b.name; // by name, only here
});The rule of thumb: define the operator when the order is a property of the object itself. Pass a comparison when it is a property of this one problem.