You can pass a function pointer, function object (or boost lambda) to std::sort to define a strict weak ordering of the elements of the container you want sorted.
However, sometimes (enough that I've hit this several times), you want to be able to chain "primitive" comparisons.
A trivial example would be if you were sorting a collection of objects that represent contact data. Sometimes you will want to sort by
last name, first name, area code. Other times
first name, last name- yet other times
age, first name, area code... etc
Now, you can certainly write an additional function object for each case, but that violates the DRY principle - especially if each comparison is less trivial.
It seems like you should be able to write a hierarchy of comparison functions - the low level ones do the single, primitive, comparisons (e.g. first name < first name), then higher level ones call the lower level ones in succession (probably chaining with && to make use of short circuit evaluation) to generate the composite functions.
The trouble with this approach is that std::sort takes a binary predicate - the predicate can only return a bool. So if you're composing them you can't tell if a "false" indicates equality or greater than. You can make your lower level predicates return an int, with three states - but then you would have to wrap those in higher level predicates before they could be used with std::sort on their own.
In all, these are not insurmountable problems. It just seems harder than it should be - and certainly invites a helper library implementation.
Therefore, does anyone know of any pre-existing library (esp. if it's a std or boost library) that can help here - of have any other thoughts on the matter?
[Update]
As mentioned in some of the comments - I've gone ahead and written my own implementation of a class to manage this. It's fairly minimal, and probably has some issues with it in general. but on that basis, for anyone interested, the class is here:
And some helper functions (to avoid the need to specify template args) is here:
The chaining solution is verbose. You could also use boost::bind in conjunction with std::logical_and to build your sorting predicate. See the linked article for more information: How the boost bind library can improve your C++ programs
Variadic templates in C++ 11 give a shorter option:
You could build a little chaining system like so:
Then to use it:
The last line is a little verbose, but I think it's clear what's intended.
You can try this:
Usage:
Implementation:
One conventional way to handle this is to sort in multiple passes and use a stable sort. Notice that
std::sort
is generally not stable. However, there’sstd::stable_sort
.That said, I would write a wrapper around functors that return a tristate (representing less, equals, greater).
std::sort
is not guaranteed to be stable because stable sorts are usually slower than non-stable ones ... so using a stable sort multiple times looks like a recipe for performance trouble...And yes it's really a shame that sort ask for a predicate: I see no other way than create a functor accepting a vector of tristate functions ...