#include <tuple>
#include <algorithm>
#include <type_traits>

template <std::size_t A, std::size_t B>
struct compare_pair {
  template <typename T>
  static void apply(T& t) {
    auto& a = std::get<A>(t);
    auto& b = std::get<B>(t);
    using std::swap;
    if (!(a < b))
      swap(a, b);
  }
};

template <typename... T> struct join_ { using type = decltype(std::tuple_cat(std::declval<T>()...)); };
template <typename... T> using join = typename join_<typename T::type...>::type;

template <std::size_t L, std::size_t R, std::size_t S,
          typename = void>
struct oddeven_range_merger {
  using type = typename join_<
    std::tuple<compare_pair<L, L+S> >,
    typename oddeven_range_merger<L+2*S, R, S>::type
  >::type;
};
template <std::size_t L, std::size_t R, std::size_t S>
struct oddeven_range_merger<L, R, S,
                            typename std::enable_if<(L >= R)>::type> {
  using type = std::tuple<>;
};

template <std::size_t L, std::size_t R, std::size_t S,
          typename = void>
struct oddeven_merger {
   using type = join<
     oddeven_merger<L, R, 2*S>,
     oddeven_merger<L+S, R, 2*S>,
     oddeven_range_merger<L+S, R-S, S> >;
};

template <std::size_t L, std::size_t R, std::size_t S>
struct oddeven_merger<L, R, S,
                      typename std::enable_if<(2*S+1 >= R-L)>::type> {
  using type = std::tuple<compare_pair<L, L+S> >;
};

template <std::size_t L, std::size_t R, typename = void>
struct oddeven_sorter {
  static constexpr std::size_t M = (L+R)/2;
  using type = join<oddeven_sorter<L, M>,
                    oddeven_sorter<M, R>,
                    oddeven_merger<L, R, 1> >;
};
template <std::size_t L, std::size_t R>
struct oddeven_sorter<L, R, typename std::enable_if<(R-L <= 1)>::type> {
  using type = std::tuple<>;
};

template <std::size_t Size>
using oddeven = typename oddeven_sorter<0, Size>::type;

template <typename... T> struct sorting_network {
  template <typename Tuple>
  static void apply(Tuple&& t) {
    using swallow = int[];
    (void)swallow{0, ((void)T::apply(t), 0)...};
  }
};
template <typename T> struct make_sorting_network {};
template <typename... T> struct make_sorting_network<std::tuple<T...> > { using type = sorting_network<T...>; };

template <typename T>
void sort_tuple(T&& tuple) {
  using network = typename make_sorting_network<oddeven<std::tuple_size<typename std::decay<T>::type >::value> >::type;
  network::apply(std::forward<T>(tuple));
}

template <typename... Args>
void sort_arguments(Args&&... args) {
  sort_tuple(std::tie(args...));
}

template <std::size_t S>
using swaps_needed = std::tuple_size<oddeven<S> >;

#include <iostream>
#include <array>
#include <utility>

template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_tuple_impl(std::basic_ostream<Ch,Tr>& os,
                      const Tuple & t,
                      std::index_sequence<Is...>) {
    using swallow = int[];
    (void)swallow{0, (void(os << (Is == 0? "" : ", ") << std::get<Is>(t)), 0)...};
}

template<class Ch, class Tr, class... Args>
decltype(auto) operator<<(std::basic_ostream<Ch, Tr>& os,
                          const std::tuple<Args...>& t) {
    os << "(";
    print_tuple_impl(os, t, std::index_sequence_for<Args...>{});
    return os << ")";
}

int main()
{
  auto t = std::make_tuple(2, 4, 3, 5, 9, 6, 1, 7, 8);
  sort_tuple(t);
  std::cout << "sorted in "
            << swaps_needed<std::tuple_size<decltype(t)>::value>::value
            << " steps: "
            << t << '\n';
}
