How does one go about sorting a vector containing custom (i.e. user defined) objects.
Probably, standard STL algorithm sort along with a predicate (a fu
Sorting such a vector
or any other applicable (mutable input iterator) range of custom objects of type X
can be achieved using various methods, especially including the use of standard library algorithms like
Since most of the techniques, to obtain relative ordering of X
elements, have already been posted, I'll start by some notes on "why" and "when" to use the various approaches.
The "best" approach will depend on different factors:
X
objects a common or a rare task (will such ranges be sorted a mutiple different places in the program or by library users)?X
objects be foolproof?If sorting ranges of X
is a common task and the achieved sorting is to be expected (i.e. X
just wraps a single fundamental value) then on would probably go for overloading operator<
since it enables sorting without any fuzz (like correctly passing proper comparators) and repeatedly yields expected results.
If sorting is a common task or likely to be required in different contexts, but there are multiple criteria which can be used to sort X
objects, I'd go for Functors (overloaded operator()
functions of custom classes) or function pointers (i.e. one functor/function for lexical ordering and another one for natural ordering).
If sorting ranges of type X
is uncommon or unlikely in other contexts I tend to use lambdas instead of cluttering any namespace with more functions or types.
This is especially true if the sorting is not "clear" or "natural" in some way. You can easily get the logic behind the ordering when looking at a lambda that is applied in-place whereas operator<
is opague at first sight and you'd have to look the definition up to know what ordering logic will be applied.
Note however, that a single operator<
definition is a single point of failure whereas multiple lambas are multiple points of failure and require a more caution.
If the definition of operator<
isn't available where the sorting is done / the sort template is compiled, the compiler might be forced to make a function call when comparing objects, instead of inlining the ordering logic which might be a severe drawback (at least when link time optimization/code generation is not applied).
class X
in order to use standard library sorting algorithmsLet std::vector
and std::vector
T::operator<(T)
or operator<(T, T)
and use standard library templates that do not expect a comparison function.Either overload member operator<
:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
or free operator<
:
struct Y {
int j{};
};
bool operator<(Y const &l, Y const &r) { return l.j < r.j; }
// ...
std::sort(vec_Y.begin(), vec_Y.end());
struct X {
int i{};
};
bool X_less(X const &l, X const &r) { return l.i < r.i; }
// ...
std::sort(vec_X.begin(), vec_X.end(), &X_less);
bool operator()(T, T)
overload for a custom type which can be passed as comparison functor.struct X {
int i{};
int j{};
};
struct less_X_i
{
bool operator()(X const &l, X const &r) const { return l.i < r.i; }
};
struct less_X_j
{
bool operator()(X const &l, X const &r) const { return l.j < r.j; }
};
// sort by i
std::sort(vec_X.begin(), vec_X.end(), less_X_i{});
// or sort by j
std::sort(vec_X.begin(), vec_X.end(), less_X_j{});
Those function object definitions can be written a little more generic using C++11 and templates:
struct less_i
{
template
bool operator()(T&& l, U&& r) const { return std::forward(l).i < std::forward(r).i; }
};
which can be used to sort any type with member i
supporting <
.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Where C++14 enables a even more generic lambda expression:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
which could be wrapped in a macro
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
making ordinary comparator creation quite smooth:
// sort by i
std::sort(v.begin(), v.end(), COMPARATOR(l.i < r.i));
// sort by j
std::sort(v.begin(), v.end(), COMPARATOR(l.j < r.j));