Какой самый простой способ определения лексикографического сравнения для элементов класса?

Если у меня есть класс, который я хочу иметь возможность сортировать (т. е. поддерживать концепцию less-than), и у него есть несколько элементов данных, таких, что мне нужно сделать лексикографический заказ, мне нужно что-то вроде этого:

struct MyData {
  string surname;
  string forename;

  bool operator<(const MyData& other) const {
    return surname < other.surname || (surname==other.surname && forename < other.forename); }
};

это становится довольно неуправляемым для чего-либо с более чем 2 членами данных. Есть ли более простые способы достичь этого? Членами данных может быть любой сопоставимый класс.

5 ответов


tuple - хорошая идея, но если вы хотите сохранить имена для переменных-членов, может быть достаточно реструктурировать вашу функцию сравнения следующим образом:

struct MyData {
    string surname;
    string forename;
    string var;
    // ...

    bool operator<(const MyData& other) const {
        if (surname != other.surname) return surname < other.surname;
        if (forename != other.forename) return forename < other.forename;
        if (var != other.var) return var < other.var;

        // ...

        return false; //< They are equal
    }
};

в зависимости от вашего вкуса, можно даже макрос как #define COMPARE(field) if (field != other.field) return field < other.field; уменьшить дублирование. Тогда функция просто станет списком COMPARE-вызовы.


С появлением C++11 появился новый и краткий способ достичь этого с помощью std:: tie:

bool operator<(const MyData& other) const {
  return std::tie(surname, forename) < std::tie(other.surname, other.forename);
}

вы можете хранить данные в boost::tuple, который обеспечивает лексикографическое сравнение и предоставляет именованные функции доступа по строкам:

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>

struct Data {
    string &surname()  {return stuff.get<0>();}
    string &forename() {return stuff.get<1>();}

    // it would be polite to add const overloads too.

    bool operator<(const Data &other) const {return stuff < other.stuff;}

private:
    boost::tuple<string, string> stuff;
};

Я считаю, что это также доступно как std::tr1::tuple и будет std::tuple в будущем стандарте.

ведение списка аксессоров, вероятно, более управляемо, чем поддержание кода сравнения.


Если все члены имеют один и тот же тип, вы можете поместить их в std::vector. По умолчанию std::lexicographical_compare будет использоваться для сравнения векторов.


можно использовать boost::tuple или std::pair который имеет встроенное лексиграфическое сравнение. Конечно, недостатком это нельзя связать метод кортежей.