#include <tuple>
#include <iostream>
#include <utility>

template <typename T>
using eval = typename T::type;
template <int i>
using int_ = std::integral_constant<int, i>;

template <typename... T>
void my_real_func(T&&... args)
{
    bool foo[] = { std::cout << args << ' '... };
}
 
template <int ... i>
struct value_list
{
    using type = value_list;
    static constexpr int size = sizeof...(i);
};

template <int N, typename M = value_list<>>
struct make_value_list;
template <int N, int... i>
struct make_value_list<N,   value_list<i...>>
     : make_value_list<N-1, value_list<0, 1+i...>> {};
template <int... i>
struct make_value_list<0, value_list<i...>>
     : value_list<i...> {};

template <int x, int y>
struct value_pair
{
    friend constexpr int_<y> lookup(int_<x>, value_pair) { return {}; }
    friend constexpr int_<x> reverse_lookup(int_<y>, value_pair) { return {}; }
};

template <typename T, typename U = eval<make_value_list<T::size>>>
struct value_map;
template <int... i, int... j>
struct value_map<value_list<i...>, value_list<j...>>
    : value_pair<i, j>...
{};

template <int... i, typename... T, int... j>
void func_(value_list<j...>, T&&... args)
{
    using tuple_type = std::tuple<T&&...>;
    tuple_type arg_tuple( std::forward<T>( args )... );
    using map_type = value_map<value_list<i...>>;
    my_real_func( std::forward<
         eval<std::tuple_element<decltype(lookup(int_<j+1>{}, map_type{}))::value, tuple_type>>>(
             std::get<decltype(lookup(int_<j+1>{}, map_type{}))::value>( arg_tuple ) )... );
}

template <int... i, typename... T>
void func(T&&... args)
{
    func_<i...>(eval<make_value_list<sizeof...(i)>>(), std::forward<T>( args )... );
}

int main()
{
    func<5, 2, 1, 4, 3>( 10, 20, 30, 40, 50 ); std::cout << '\n';
}