Making a variadic templete from another variadic template

Yes, it is possible:

template< typename F, typename S >
class trans {};

template< typename F, typename S, typename... Tail >
struct create_trans_chain;

template< typename F, typename S, typename... Tail >
using create_trans_chain_t = typename create_trans_chain< F, S, Tail... >::type;

template< typename F, typename S >
struct create_trans_chain< F, S >
{
    using type = std::tuple< trans< F, S > >;
};

template< typename F, typename S, typename Next, typename... Tail >
struct create_trans_chain< F, S, Next, Tail... >
{
    using type = decltype(std::tuple_cat(
        std::declval< create_trans_chain_t< F, S > >(),
        std::declval< create_trans_chain_t< S, Next, Tail... > >()));
};

With Boost.Mp11, this is pretty short (as always):

template <typename ...Args>
using trans_chain_create_t =
    mp_transform<trans,
        mp_pop_back<std::tuple<Args...>>,
        mp_pop_front<std::tuple<Args...>>>;

mp_transform is basically a zip, we're zipping (Args without the tail) with (Args without the head) and then pairwise applying trans to that.


You can split the above by adding a helper metafunction, zip_tail:

template <template <typename...> class F, typename L>
using zip_tail = mp_transform<F, mp_pop_back<L>, mp_pop_front<L>>;

template <typename ...Args>
using trans_chain_create_t = zip_tail<trans, std::tuple<Args...>>;

Simply unroll over a recursive template with an end specialization. How it works is described inside the code in comments. Take a look:

class json; // as you like that in your given code example... we need to define it
using input = std::tuple< std::string, int, float, std::string, json >;

// First we define a template struct which takes 1 parameter
// No need for a definition as we specialize later
template <typename INPUT >
struct Transform;

// for all inputs which have at minimum 3 template parameters 
// inside the std::tuple parameter we use this specialization 
template <typename FIRST, typename SECOND, typename NEXT, typename ... TAIL >
struct Transform< std::tuple<FIRST, SECOND, NEXT, TAIL...>>
{
    // As we have more than 2 parameters, we continue to transform
    // simply by using a recursive "call" to out Transform
    // struct
    using OUT = decltype( std::tuple_cat( 
        std::tuple< std::pair< FIRST, SECOND >>(),
        std::declval<typename Transform< std::tuple<SECOND, NEXT, TAIL...>>::OUT>()
        ));        
};

// This specialization is used for the last input as
// it has exactly 2 parameters  
template <typename FIRST, typename SECOND >
struct Transform< std::tuple<FIRST, SECOND >>
{
    using OUT = typename std::tuple<std::pair < FIRST, SECOND>>;
};

using OUT = Transform< input >::OUT;

template < typename T>
void Print()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    Print< Transform< input >::OUT >();
}

There is no need to define your own template <typename F, typename S> class trans {...}; as we have std::pair;