Есть структура с несколькими полями struct P { std::string name int year int month } Как сравнить два таких объекта, так чтобы сначала они сравнивались по дате, а потом по имени?
Ответ Для лексиграфического сравнения объектов по нескольким полям можно использовать функцию std::tie. bool operator < (const P& a, const P& b) { return std::tie(a.year, a.month, a.name) < std::tie(b.year, b.month, b.name) // сначала сравнивается year, потом month, потом name. } std::tie возвращает временный объект - кортеж ссылок на поля std::tuple, у которого уже вызывается оператор "меньше". Остальные операторы сравнения можно получить из оператора "меньше", написав их самому, либо при помощи std::rel_ops или Boost.Operators. bool operator > (const P& a, const P& b) { return b < a } bool operator <= (const P& a, const P& b) { return !(b < a) } bool operator >= (const P& a, const P& b) { return !(a < b) } Чтобы избежать дублирования кода, можно написать вспомогательную функцию, которая будет превращать структуру в кортеж ссылок: bool operator < (const P& a, const P& b) { auto tuple = [](const P& p) { return std::tie(p.year, p.month, p.name) } return tuple(a) < tuple(b) } Оператор сравнения можно также сделать членом самой структуры: struct P { std::string name int year int month bool operator < (const P& other) const { return std::tie(year, month, name) < std::tie(other.year, other.month, other.name) } } Так как сравнение не меняет саму структуру, то аргумент должен быть константной ссылкой, и сама функция должна быть константной. В случае данной структуры, нет никакой разницы между свободной функцией и функцией-членом класса. Однако если у структуры есть конструктор, позволяющий неявные преобразования типов, то надо использовать только свободную функцию: struct Complex { Complex(int r = 0, int i = 0) : r(r), i(i) {} int r, i } bool operator<(const Complex& a, const Complex& b) <br>int main() { Complex c(3, 4) c < 1 // свободная функция operator<(const Complex&, const Complex&), // один из аргументов - Complex, для второго аргумента делается // неявный вызов Complex(1), получается operator<(c, Complex(1)) 1 < c // то же самое, получается operator<(Complex(1), c) } <br>Если бы operator< был не свободной функцией, а функцией-членом Complex, то код 1 < c не скомпилировался бы т.к. у 1 (тип int) нет метода <.<br>