Какой самый простой способ определения лексикографического сравнения для элементов класса?
Если у меня есть класс, который я хочу иметь возможность сортировать (т. е. поддерживать концепцию 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
который имеет встроенное лексиграфическое сравнение. Конечно, недостатком это нельзя связать метод кортежей.