#include <iostream>
#include <typeinfo>

using namespace std;


/// Helper class to wrap incomplete types and avoid instantiation of T
template<class T> struct Wrapper {};


namespace CTList {

    /// The front of compile-time lists
    struct Nil {};

} //namespace


/// Compile-time list helper
template< typename ListId, typename Item >
Item NextInListHelper( ::Wrapper<ListId>, ::Wrapper<Item> );

#define Back(ListId) \
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
    decltype( NextInListHelper( ::Wrapper<ListId>(), ::Wrapper<\
                             CTList::Nil \
     >())) \
     >())) \
     >())) \
     >())) \
     >())) \
     >())) \
     >())) \
     >())) \
     >())) \
     >()))



/// Add a new element (type) to the list
#define PushBack( ListId, item) \
    item NextInListHelper( ::Wrapper< ListId >, ::Wrapper< Back(ListId) > )

/// The next element in the ('ListId') list after 'item'
#define Next(ListId, item) decltype(NextInListHelper(::Wrapper<ListId>(), ::Wrapper<item>() ))




struct A {};


namespace NS1 {
    struct B {};
    struct C {};
    struct D {};

    // building up the compile-time list
    struct Head;

    PushBack(Head, A);
    PushBack(Head, B);

}

PushBack(NS1::Head, NS1::C);

namespace NS1 {
    PushBack(Head, D);
}



namespace NS2 {

    // iterate through the list
    template <class ListId, class Item>
    void print(Wrapper<Item>, Wrapper<Item>) {}

    template <class ListId, class PrevItem, class Item>
    void print(Wrapper<PrevItem>, Wrapper<Item>)
    {
        cout << typeid(Item).name() << endl;
        print<ListId>(Wrapper<Item>(), Wrapper< Next(ListId, Item) >());
    }

}


#include <vector>
#include <string>

namespace CTList {


    /// Helper for iterating through compile-time lists
    template<class ListId, class PrevItem, class Item>
    struct Iterator {};

    /// Workaround for gcc's decltype():: bug
    template<class Iterator> struct IterTraits{};
    template<class ListId, class PrevItem, class Item>
    struct IterTraits<Iterator<ListId, PrevItem, Item>>
    {
        typedef ListId id;
        typedef Item item;
        typedef PrevItem prev;

    };

}


/// Iterator to the first element
#define Begin(ListId) CTList::Iterator<ListId, CTList::Nil, Next(ListId, CTList::Nil)>()

/// Iterator to the next element after iterator @c it
#define IteratorInc(it)  \
    CTList::Iterator< \
        typename CTList::IterTraits<decltype(it)>::id, \
        typename CTList::IterTraits<decltype(it)>::item, \
        Next( \
            typename CTList::IterTraits<decltype(it)>::id,  \
            typename CTList::IterTraits<decltype(it)>::item \
        ) \
    >()

namespace NS3 {

    // iterating through the list with an 'iterator'
    template <class UserData, class ListId, class Item>
    void process(UserData&, CTList::Iterator<ListId, Item, Item> ) {}

    template <class UserData, class ListId, class PrevItem, class Item>
    void process(UserData& u, CTList::Iterator<ListId, PrevItem, Item> it)
    {
        u.push_back(typeid(Item).name());
        process(u, IteratorInc(it));
    }

}

int main()
{
    NS2::print<NS1::Head>(::Wrapper<CTList::Nil>(), ::Wrapper<Next(NS1::Head, CTList::Nil)>() );

    vector<string> a, b = { typeid(A).name(), typeid(NS1::B).name() , typeid(NS1::C).name(), typeid(NS1::D).name() };
    NS3::process(a, Begin(NS1::Head));
    if (a == b) cout << "Passed!\n";
    return 0;
}









