Q:

Create cartesian product expansion of two variadic, non-type template parameter packs

Lets say, I have 

two lists of non-type template parameteres (which might have a different type)
a template foo that takes one value of each of those lists as a parameter 

How can I create a variadic parameter pack of foos, parameterized with the cartesian product of the two list elements?
Here is what I mean:
template<int ...>
struct u_list {};

template<char ...>
struct c_list {};

template<int, char >
struct foo {};

template<class ...>
struct bar {};

using int_vals = u_list<1, 5, 7>;
using char_vals = c_list<-3, 3>;

using result_t = /* magic happens*/
using ref_t = bar<
    foo<1, -3>, foo<1, 3>,
    foo<5, -3>, foo<5, 3>,
    foo<7, -3>, foo<7, 3>
>;

static_assert(std::is_same<result_t, ref_t >::value, "");

I'm looking for a solution that works in c++11 and doesn't use any libraries except the c++11 standard library. I also have my handroled version of c++14's index_sequence / make_index_sequence and can provide the non-type parameter lists as arrays if that simplifies the code.
The closest I've found so far is this: How to create the Cartesian product of a type list?. So in principle (I haven't tested it) it should be possible to turn the non-type parameter packs into type parameter packs and then apply the solution in the linked post, but I was hoping that there is a simpler / shorter solution along the lines of this:
template<int... Ints, char ... Chars>
auto magic(u_list<Ints...>, c_list<Chars...>) 
{
    //Doesn't work, as it tries to expand the parameter packs in lock step
    return bar<foo<Ints,Chars>...>{};  
}

using result_t = decltype(magic(int_vals{}, char_vals{}));

A:

You may do something like the following:
template <int... Is>
using u_list = std::integer_sequence<int, Is...>;

template <char... Cs>
using c_list = std::integer_sequence<char, Cs...>;

template<int, char> struct foo {};

template<class ...> struct bar {};

template <std::size_t I, typename T, template <typename, T...> class C, T ... Is>
constexpr T get(C<T, Is...> c)
{
    constexpr T values[] = {Is...};
    return values[I];
}

template <std::size_t I, typename T>
constexpr auto get_v = get<I>(T{});

template<int... Ints, char ... Chars, std::size_t ... Is>
auto cartesian_product(u_list<Ints...>, c_list<Chars...>, std::index_sequence<Is...>)
-> bar<foo<
        get_v<Is / sizeof...(Chars), u_list<Ints...> >,
        get_v<Is % sizeof...(Chars), c_list<Chars...> >
        >...
    >;

template<int... Ints, char ... Chars>
auto cartesian_product(u_list<Ints...> u, c_list<Chars...> c)
-> decltype(cartesian_product(u, c, std::make_index_sequence<sizeof...(Ints) * sizeof...(Chars)>()));

using int_vals = u_list<1, 5, 7>;
using char_vals = c_list<-3, 3>;

using result_t = decltype(cartesian_product(int_vals{}, char_vals{}));

Demo
Possible implementation of std part:
template <typename T, T ... Is> struct integer_sequence{};

template <std::size_t ... Is>
using index_sequence = integer_sequence<std::size_t, Is...>;

template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};

And change in answer:
template <std::size_t I, typename T, template <typename, T...> class C, T ... Is>
constexpr T get(C<T, Is...> c)
{
    using array = T[];
    return array{Is...}[I];
}

template<int... Ints, char ... Chars, std::size_t ... Is>
auto cartesian_product(u_list<Ints...>, c_list<Chars...>, index_sequence<Is...>)
-> bar<foo<
        get<Is / sizeof...(Chars)>(u_list<Ints...>{}),
        get<Is % sizeof...(Chars)>(c_list<Chars...>{})
        >...
    >;

Demo C++11

