#include <iostream>

template <unsigned N>
class element {
public:
    const static unsigned value = N;
};

template <typename ...Elems>
class set {
};

template <typename T, typename U>
class join;

template <typename ...Elems>
class join<set<>, set<Elems...>> {
public:
    typedef set<Elems...> type;
};

template <typename Elem1, typename ...Elems, typename ...Elems2>
class join<set<Elem1, Elems...>, set<Elems2...>> {
public:
    typedef typename join<set<Elems...>, set<Elem1, Elems2...>>::type type;
};


template <typename T, typename U>
class all_subsets_worker;

template <typename Rest>
class all_subsets_worker<set<>, Rest>
{
public:
    typedef set<Rest> type;
};

template <typename Elem, typename Rest, typename ...Elems>
class all_subsets_worker<set<Elem, Elems...>, Rest>
{
public:
    typedef typename join<
                typename all_subsets_worker<set<Elems...>, Rest>::type,
                typename all_subsets_worker<set<Elems...>, typename join< set<Elem>, Rest>::type >::type
            >::type type;
};

template <typename T>
class all_subsets;

template <typename Elem, typename ...Elems>
class all_subsets<set<Elem, Elems...>> {
public:
    typedef typename all_subsets_worker<set<Elem, Elems...>, set<>>::type type;
};

int main(int argc, const char * argv[])
{
    auto t = all_subsets<set<element<0>, element<1>, element<2>, element<3>>>::type();

    double u = t;

    // insert code here...
    std::cout << "Hello, World!\n";
    return 0;
}
