-
Notifications
You must be signed in to change notification settings - Fork 58
Sorter facade
The Sorter
and ComparisonSorter
concepts require sorter implementers to implement a variety of operator()
overloads with a rather high redundancy factor. Therefore, cpp-sort provides a wapper class which makes creating sorters easier by generating most of the boilerplate for the required operations in the simplest cases. To use it, one needs to create a sorter implementation and to wrap it into sorter_facade
:
struct frob_sorter_impl
{
// Regular sorter code
};
struct frob_sorter:
cppsort::sorter_facade<frob_sorter_impl>
{};
sorter_facade
provides the following member functions so that a sorter can be turned into a function pointer:
template<typename Iterable>
operator Ret(*)(Iterable&)() const;
template<typename Iterable, typename Compare>
operator Ret(*)(Iterable&, Compare)() const;
template<typename Iterator>
operator Ret(*)(Iterator, Iterator)() const;
template<typename Iterator, typename Compare>
operator Ret(*)(Iterator, Iterator, Compare)() const;
Note that the function pointer conversion syntax above is made up, but it allows to clearly highlight what it does while hiding the ugly typedef
s needed for the syntax to be valid. In these signatures, Ret
is an std::result_of_t
of the parameters (well, it is what you would expect it to be).
sorter_facade
provides overloads operator()
to handle ranges:
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> decltype(Sorter::operator()(std::begin(iterable), std::end(iterable)));
template<typename Iterable, typename Compare>
auto operator()(Iterable& iterable, Compare compare) const
-> decltype(Sorter::operator()(std::begin(iterable), std::end(iterable), compare));
This overload simply calls the operator()
overloads taking two iterators by using std::begin
and std::end
on iterable
. When implementing your own sorters, these overloads will be hidden by default but you can import them in the class with a using
directive.
Provided you have a sorting function with a standard iterator interface, creating the corresponding sorter becomes trivial thanks to sorter_facade
. For instance, here is a simple sorter wrapping std::sort
:
struct std_sorter_impl
{
template<
typename RandomAccessIterator,
typename Compare = std::less<>
>
auto operator()(RandomAccessIterator first,
RandomAccessIterator last,
Compare compare={}) const
-> void
{
std::sort(first, last, compare);
}
};
struct std_sorter:
cppsort::sorter_facade<std_sorter_impl>
{};
cpp-sort considers that every collection sorted without a specific comparison function shoud work as if it was sorted with std::less<>
. However, some sorters do not implement comparison sorts and therefore do
not provide overloads for operator()
taking custom comparison functions.
sorter_facade
provides the following overloads so that every sorter, even non-comparison sorters, can be passed std::less<>
or std::less<T>
where T
is the type of the values to sort:
template<typename Iterable>
auto operator()(Iterable& iterable, std::less<>) const
-> decltype(Sorter::operator()(iterable));
template<typename Iterator>
auto operator()(Iterator first, Iterator last, std::less<>) const
-> decltype(Sorter::operator()(first, last));
template<typename Iterable>
auto operator()(Iterable& iterable,
std::less<typename std::iterator_traits<decltype(std::begin(iterable))>::value_type>) const
-> decltype(Sorter::operator()(iterable));
template<typename Iterator>
auto operator()(Iterator first, Iterator last,
std::less<typename std::iterator_traits<Iterator>::value_type>) const
-> decltype(Sorter::operator()(first, last));
While is does not appear in the signatures above, there are some SFINAE tricks to ensure that these overloads are generated only if the adapted sorter is not already a comparison sorter, but also to handle some tricky corner cases.
- Home
- Quickstart
- Sorting library
- Comparators and projections
- Miscellaneous utilities
- Tutorials
- Tooling
- Benchmarks
- Changelog
- Original research