While implementing a variation of a binary search problem, I needed to reorder slicing points (i.e start, mid, end) so that they are stored within the corresponding variable (e.g. (1,5,2) -> (1,2,5)
). This is fairly simple to do with a few if statements
and swaps
. However as a thought experiment, I'm now interested in generalizing this to work with n
many T
type variables. I started experimenting with some intuitive solutions and as a starting place, I came up with this template function:
template<typename T>
void
sortInPlace(
std::function<bool (const T&, const T&)> compareFunc,
T& start,
T& mid,
T& end)
{
std::vector<T> packed {start, mid, end};
std::sort(packed.begin(), packed.end(), compareFunc);
auto packedAsTuple = make_tuple(packed[0], packed[1], packed[2]);
std::tie(start, mid, end) = packedAsTuple;
}
And when I ran the following, using typedef std::pair<int,int> Pivot
:
//Comparison function to sort by pair.first, ascending:
std::function<bool(const Pivot&, const Pivot&)>
comp =[](const Pivot & a, const Pivot & b) {
return std::get < 0 > (a) < std::get < 0 > (b);
};
int main(){
Pivot a(8,1);
Pivot b(2,3);
Pivot c(4,6);
sortInPlace(comp,a,b,c);
}
This turns out to work as intended:
a after sort: 2, 3
b after sort: 4, 6
c after sort: 8, 1
Ideally, the following step is to convert this template into a variadic template but I'm having trouble achieving this. I also have a few things that bother me regarding the current version:
std::vector
was an arbitrary decision. I've done this because it's unclear to me what structure/container is the best to use in packing of these values. Seems to me that the choice of structure needs to be constructed, sorted and unpacked/converted to tuples easily and I'm not sure if there is such a magical structure out there.std::tie
or any other unpacking/moving operation with variable number (i.e. unknown in compile-time) of elements. I embarked on this thought experiment expecting to end up with a syntactically-correct version of std::move(std::sort({x,y,z}, comp), {x,y,z})
and considering where my research has led me so far, I'm starting to think I'm over-complicating this problem. Any help, insight or suggestion would be much appreciated!
One possible C++17 solution with std::sort
that generalizes your example:
template<class Comp, class... Ts>
void my_sort(Comp comp, Ts&... values) {
using T = std::common_type_t<Ts...>;
T vals[]{std::move(values)...};
std::sort(std::begin(vals), std::end(vals), comp);
auto it = std::begin(vals);
((values = std::move(*it++)), ...);
}
using Pivot = std::pair<int, int>;
const auto comp = [](Pivot a, Pivot b) {
return std::get<0>(a) < std::get<0>(b);
};
Pivot a(8, 1);
Pivot b(2, 3);
Pivot c(4, 6);
my_sort(comp, a, b, c);
If the number N
of parameters in the pack is small, you don't need std::sort
at all. Just a series of (hardcoded) comparisons (and for small N
the minimum number of comparisons is known exactly) will do the job - see sec. 5.3 Optimum sorting of Knuth's TAOCP vol. 3.