#include <algorithm>
#include <cstdint>
#include <iterator>
#include <iostream>
#include <tuple>
#include <vector>

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

template <typename Seq, typename T1, typename T2>
struct cartesian_pairs_helper;

template <std::size_t...Is, typename T1, typename T2>
struct cartesian_pairs_helper<std::index_sequence<Is...>, T1, T2>
{
	static constexpr std::size_t size1 = std::tuple_size<T1>::value;
	using type = std::tuple<
		std::pair<
			std::tuple_element_t<Is / size1, T1>,
			std::tuple_element_t<Is % size1, T2>
			>...>;
};

template <typename T1, typename T2>
struct cartesian_pairs
{
	using type = typename cartesian_pairs_helper<
		std::make_index_sequence<std::tuple_size<T1>::value
								 * std::tuple_size<T2>::value>,
		T1, T2>::type;
};

static_assert(std::is_same<
	std::tuple<
		std::pair<char, float>,
		std::pair<char, double>,
		std::pair<int, float>,
		std::pair<int, double>>,
	cartesian_pairs<std::tuple<char, int>, std::tuple<float, double>>::type
	>::value, "unexpected");

int main() {
}
