#include <iostream>
#include <tuple>
#include <type_traits>
template <typename T> struct Identity { using type = T; };
// Merging packs of types.
template <typename...> struct MergePacks;
template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};
template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};
// Appending a type to a pack.
template <typename Pack, typename T> struct AppendType;
template <template <typename...> class P, typename... Ts, typename T>
struct AppendType <P<Ts...>, T> {
using type = P<Ts..., T>;
};
// ExpandPackWithTuple takes a pack, and creates N packs that each end with the tuple's elements, N is the size of the tuple.
template <template <typename...> class P, typename Pack, typename Tuple, typename Indices> struct ExpandPackWithTupleHelper;
template <template <typename...> class P, typename Pack, typename Tuple, std::size_t... Is>
struct ExpandPackWithTupleHelper<P, Pack, Tuple, std::index_sequence<Is...>> {
using type = P<typename AppendType<Pack, typename std::tuple_element<Is, Tuple>::type>::type...>;
};
template <template <typename...> class P, typename Pack, typename Tuple>
using ExpandPackWithTuple = typename ExpandPackWithTupleHelper<P, Pack, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;
// Now, for TupleTree itself.
template <template <typename...> class P, typename OutputPack, typename... Tuples> struct TupleTreeHelper;
template <template <typename...> class P, typename... Ts, typename First, typename... Rest>
struct TupleTreeHelper<P, P<Ts...>, First, Rest...> : TupleTreeHelper<P, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};
template <template <typename...> class P, typename OutputPack>
struct TupleTreeHelper<P, OutputPack> {
using type = OutputPack;
};
template <template <typename...> class P, typename... Tuples>
using TupleTree = typename TupleTreeHelper<P, P<P<>>, Tuples...>::type;
// Testing
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
int main() {
std::cout << std::boolalpha << std::is_same<
TupleTree<Pack, T1, T2>,
Pack<
Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
>
>::value << '\n'; // true
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHVwbGU+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KCnRlbXBsYXRlIDx0eXBlbmFtZSBUPiBzdHJ1Y3QgSWRlbnRpdHkgeyB1c2luZyB0eXBlID0gVDsgfTsKCi8vIE1lcmdpbmcgcGFja3Mgb2YgdHlwZXMuCnRlbXBsYXRlIDx0eXBlbmFtZS4uLj4gc3RydWN0IE1lcmdlUGFja3M7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgUGFjaz4Kc3RydWN0IE1lcmdlUGFja3M8UGFjaz4gOiBJZGVudGl0eTxQYWNrPiB7fTsKCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4+IGNsYXNzIFAsIHR5cGVuYW1lLi4uIFR5cGVzMSwgdHlwZW5hbWUuLi4gVHlwZXMyLCB0eXBlbmFtZS4uLiBQYWNrcz4Kc3RydWN0IE1lcmdlUGFja3M8UDxUeXBlczEuLi4+LCBQPFR5cGVzMi4uLj4sIFBhY2tzLi4uPiA6IE1lcmdlUGFja3M8UDxUeXBlczEuLi4sIFR5cGVzMi4uLj4sIFBhY2tzLi4uPiB7fTsKCi8vIEFwcGVuZGluZyBhIHR5cGUgdG8gYSBwYWNrLgp0ZW1wbGF0ZSA8dHlwZW5hbWUgUGFjaywgdHlwZW5hbWUgVD4gc3RydWN0IEFwcGVuZFR5cGU7Cgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lLi4uPiBjbGFzcyBQLCB0eXBlbmFtZS4uLiBUcywgdHlwZW5hbWUgVD4Kc3RydWN0IEFwcGVuZFR5cGUgPFA8VHMuLi4+LCBUPiB7Cgl1c2luZyB0eXBlID0gUDxUcy4uLiwgVD47Cn07CgovLyBFeHBhbmRQYWNrV2l0aFR1cGxlIHRha2VzIGEgcGFjaywgYW5kIGNyZWF0ZXMgTiBwYWNrcyB0aGF0IGVhY2ggZW5kIHdpdGggdGhlIHR1cGxlJ3MgZWxlbWVudHMsIE4gaXMgdGhlIHNpemUgb2YgdGhlIHR1cGxlLgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lLi4uPiBjbGFzcyBQLCB0eXBlbmFtZSBQYWNrLCB0eXBlbmFtZSBUdXBsZSwgdHlwZW5hbWUgSW5kaWNlcz4gc3RydWN0IEV4cGFuZFBhY2tXaXRoVHVwbGVIZWxwZXI7Cgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lLi4uPiBjbGFzcyBQLCB0eXBlbmFtZSBQYWNrLCB0eXBlbmFtZSBUdXBsZSwgc3RkOjpzaXplX3QuLi4gSXM+CnN0cnVjdCBFeHBhbmRQYWNrV2l0aFR1cGxlSGVscGVyPFAsIFBhY2ssIFR1cGxlLCBzdGQ6OmluZGV4X3NlcXVlbmNlPElzLi4uPj4gewoJdXNpbmcgdHlwZSA9IFA8dHlwZW5hbWUgQXBwZW5kVHlwZTxQYWNrLCB0eXBlbmFtZSBzdGQ6OnR1cGxlX2VsZW1lbnQ8SXMsIFR1cGxlPjo6dHlwZT46OnR5cGUuLi4+Owp9OwoKdGVtcGxhdGUgPHRlbXBsYXRlIDx0eXBlbmFtZS4uLj4gY2xhc3MgUCwgdHlwZW5hbWUgUGFjaywgdHlwZW5hbWUgVHVwbGU+CnVzaW5nIEV4cGFuZFBhY2tXaXRoVHVwbGUgPSB0eXBlbmFtZSBFeHBhbmRQYWNrV2l0aFR1cGxlSGVscGVyPFAsIFBhY2ssIFR1cGxlLCBzdGQ6Om1ha2VfaW5kZXhfc2VxdWVuY2U8c3RkOjp0dXBsZV9zaXplPFR1cGxlPjo6dmFsdWU+Pjo6dHlwZTsKCi8vIE5vdywgZm9yIFR1cGxlVHJlZSBpdHNlbGYuCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4+IGNsYXNzIFAsIHR5cGVuYW1lIE91dHB1dFBhY2ssIHR5cGVuYW1lLi4uIFR1cGxlcz4gc3RydWN0IFR1cGxlVHJlZUhlbHBlcjsKCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4+IGNsYXNzIFAsIHR5cGVuYW1lLi4uIFRzLCB0eXBlbmFtZSBGaXJzdCwgdHlwZW5hbWUuLi4gUmVzdD4Kc3RydWN0IFR1cGxlVHJlZUhlbHBlcjxQLCBQPFRzLi4uPiwgRmlyc3QsIFJlc3QuLi4+IDogVHVwbGVUcmVlSGVscGVyPFAsIHR5cGVuYW1lIE1lcmdlUGFja3M8RXhwYW5kUGFja1dpdGhUdXBsZTxQLCBUcywgRmlyc3Q+Li4uPjo6dHlwZSwgUmVzdC4uLj4ge307Cgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lLi4uPiBjbGFzcyBQLCB0eXBlbmFtZSBPdXRwdXRQYWNrPgpzdHJ1Y3QgVHVwbGVUcmVlSGVscGVyPFAsIE91dHB1dFBhY2s+IHsKCXVzaW5nIHR5cGUgPSBPdXRwdXRQYWNrOwp9OwoKdGVtcGxhdGUgPHRlbXBsYXRlIDx0eXBlbmFtZS4uLj4gY2xhc3MgUCwgdHlwZW5hbWUuLi4gVHVwbGVzPgp1c2luZyBUdXBsZVRyZWUgPSB0eXBlbmFtZSBUdXBsZVRyZWVIZWxwZXI8UCwgUDxQPD4+LCBUdXBsZXMuLi4+Ojp0eXBlOwoKLy8gVGVzdGluZwp0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4+IHN0cnVjdCBQYWNrOwp1c2luZyBUMSA9IHN0ZDo6dHVwbGU8aW50LCBjaGFyLCBkb3VibGU+Owp1c2luZyBUMiA9IHN0ZDo6dHVwbGU8Ym9vbCwgZG91YmxlLCBpbnQsIGNoYXI+OwoKaW50IG1haW4oKSB7CglzdGQ6OmNvdXQgPDwgc3RkOjpib29sYWxwaGEgPDwgc3RkOjppc19zYW1lPAoJCVR1cGxlVHJlZTxQYWNrLCBUMSwgVDI+LAoJCVBhY2s8CgkJCVBhY2s8aW50LCBib29sPiwgUGFjazxpbnQsIGRvdWJsZT4sIFBhY2s8aW50LCBpbnQ+LCBQYWNrPGludCwgY2hhcj4sCgkJCVBhY2s8Y2hhciwgYm9vbD4sIFBhY2s8Y2hhciwgZG91YmxlPiwgUGFjazxjaGFyLCBpbnQ+LCBQYWNrPGNoYXIsIGNoYXI+LAoJCQlQYWNrPGRvdWJsZSwgYm9vbD4sIFBhY2s8ZG91YmxlLCBkb3VibGU+LCBQYWNrPGRvdWJsZSwgaW50PiwgUGFjazxkb3VibGUsIGNoYXI+CgkJPgoJPjo6dmFsdWUgPDwgJ1xuJzsgIC8vIHRydWUKfQo=