Вы можете использовать кортеж, чтобы легко получить лексикографический порядок ваших членов:
return std::tie(lhs.i, lhs.f, lhs.c) < std::tie(rhs.i, rhs.f, rhs.c);
Для этого требуется, чтобы каждый член был сопоставимого типа, например, lhs.i < rhs.i
имеет смысл.
Обратите внимание, что std::tie
и std::tuple
доступны только для C ++ 11, поэтому для C ++ 03 вы можете использовать, например, Boost.Tuple, который обеспечивает boost::tie
(boost::tuple
использует тот же порядок, что и std::tuple
).
Относительно того, куда это должно пойти, принято указывать это в operator<
(после всего этого в первую очередь возможно использование tie
для простого заказа).,Довольно часто этот оператор будет другом, поэтому он будет выглядеть следующим образом:
class foo {
public:
/* public interface goes here */
// declaration of non-member friend operator
// if it doesn't need to be a friend, this declaration isn't needed
friend
bool operator<(foo const& lhs, foo const& rhs);
private:
T t;
U u;
V v;
};
bool operator<(foo const& lhs, foo const& rhs)
{
// could be boost::tie
return std::tie(lhs.t, lhs.u, lhs.v) < std::tie(rhs.t, rhs.u, rhs.v);
}
Как вы можете видеть, он не полностью автоматический, так как реализация operator<
должна перечислять каждого члена foo
(илипо крайней мере те, которые имеют значение для заказа), дважды.Боюсь, нет лучшего способа.
Вместо предоставления operator<
вы можете специализировать std::less
для foo
, но это немного экзотично и не является предпочтительным способом.Если упорядочение по-прежнему не имеет смысла быть частью расширенного интерфейса foo
(например, может быть более одного упорядочения, которое имеет смысл без канонического), тогда предпочтительным способом является написание функтора:
struct foo_ordering {
bool operator()(foo const& lhs, foo const& rhs) const
{
/* implementation as before, but access control/friendship
has to be planned for just like for operator< */
}
};
Тогда вы будете использовать, например, std::set<foo, foo_ordering>
.
Имейте в виду, что независимо от того, какую форму принимает заказ (через operator<
, std::less<foo>
или функтор), если он используетсяс std::set
или любым другим ассоциативным контейнером (и по умолчанию, например, std::set<T>
использует std::less<T>
, который, в свою очередь, использует operator<
по умолчанию), он должен следовать некоторым строгим критериям, то есть это должен быть строгий слабый порядок.Однако если все элементы, которые используются для заказа foo
, имеют заказы SW, то результирующее лексикографическое упорядочение также является заказом SW.