#include<tuple>
#include<vector>

#include<iostream>

template<typename... Ps>
inline void 
cross_imp(std::tuple<Ps...> pref, std::vector<std::tuple<Ps...>>& out) 
{
    out.push_back(pref);
}

template<typename... Ps, typename H, typename... Ts>
inline void 
cross_imp(std::tuple<Ps...> pref,
                      std::vector<std::tuple<Ps..., H, Ts...>>& out,
                      std::vector<H> h, std::vector<Ts>... t) 
{
    for(H he: h)
		cross_imp(std::tuple_cat(pref, std::make_tuple(he)), out, t...);
}

template<typename... Ts>
std::vector<std::tuple<Ts...>> 
cross(std::vector<Ts>... in) 
{
	std::vector<std::tuple<Ts...>> res;
	cross_imp(std::tuple<>(), res, in...);
	return res;
}

#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>

template<size_t N>
struct Apply {
    template<typename F, typename T, typename... A>
    static inline auto apply(F&& f, T && t, A &&... a)
        -> decltype(Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
            ::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
        ))
    {
        return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
            ::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
        );
    }
};

template<>
struct Apply<0> {
    template<typename F, typename T, typename... A>
    static inline auto apply(F && f, T &&, A &&... a)
        -> decltype(f(::std::forward<A>(a)...))
    {
        return f(::std::forward<A>(a)...);
    }
};

template<typename F, typename T>
inline auto apply(F && f, T && t)
     -> decltype(Apply< ::std::tuple_size<
         typename ::std::decay<T>::type
     >::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)))
{
    return Apply< ::std::tuple_size<
        typename ::std::decay<T>::type
    >::value>::apply(f, ::std::forward<T>(t));
}

int main() {
	std::vector<int>         is  = { 2, 5, 9 };
	std::vector<char const*> cps = { "foo","bar" };
	std::vector<float>       fs  = { 1.5, 9.3, 1.2 };
	std::vector<double>      ds  = { 9.2,-2.1, 2.3 };

#ifdef DIRECT_CALL
	auto result = cross( is, cps, fs, ds );
#else
	std::vector< std::tuple<int,char const*,float,double> > result
		= apply( cross, std::make_tuple( is, cps, fs, ds ));    
#endif

	for(auto& a: result) {
		std::cout << '{' 
			<< std::get<0>(a) << ',' 
			<< std::get<1>(a) << ',' 
			<< std::get<2>(a) << ',' 
			<< std::get<3>(a) 
		<< '}' << std::endl;
	}
}