#include <string>
#include <iostream>
#include <utility>
#include <type_traits>

template <char... c> struct literal
{
    static constexpr char str[sizeof...( c ) + 1] = { c... };
    typedef literal type;
};
template <char... c>
constexpr char literal<c...>::str[];

template <typename... s> struct concat
    : concat<typename s::type...> {};
template <char... c1, char... c2, typename... s> struct concat<literal<c1...>,literal<c2...>, s...>
    : concat<literal<c1..., c2...>, s...> {};
template <char... c> struct concat<literal<c...>>
    : literal<c...> {};
template <> struct concat<>
    : literal<> {};

template <std::size_t N, typename L = literal<>> struct N_to_literal
    : N_to_literal<N / 10, concat<literal<('0' + N % 10)>,L>> {};
template <typename L> struct N_to_literal<0, L>
    : L {};
template <> struct N_to_literal<0, literal<>>
    : literal<'0'> {};

template <typename T> struct tag {};

template <typename T, typename U> struct map_pair
{
    friend U lookup(tag<T>, map_pair);
};
literal<'u','n','k','n','o','w','n'> lookup(...);

template <typename... T> struct type_map : T... {};

typedef type_map<
    map_pair<void,               literal<'v','o','i','d'>>,
    map_pair<char,               literal<'c','h','a','r'>>,
    map_pair<signed char,        literal<'s','i','g','n','e','d',' ','c','h','a','r'>>,
    map_pair<unsigned char,      literal<'u','n','s','i','g','n','e','d',' ','c','h','a','r'>>,
    map_pair<short,              literal<'s','h','o','r','t'>>,
    map_pair<unsigned short,     literal<'u','n','s','i','g','n','e','d',' ','s','h','o','r','t'>>,
    map_pair<int,                literal<'i','n','t'>>,
    map_pair<unsigned,           literal<'u','n','s','i','g','n','e','d'>>,
    map_pair<long,               literal<'l','o','n','g'>>,
    map_pair<unsigned long,      literal<'u','n','s','i','g','n','e','d',' ','l','o','n','g'>>,
    map_pair<long long,          literal<'l','o','n','g',' ','l','o','n','g'>>,
    map_pair<unsigned long long, literal<'u','n','s','i','g','n','e','d',' ','l','o','n','g',' ','l','o','n','g'>>,
    map_pair<wchar_t,            literal<'w','c','h','a','r','_','t'>>,
    map_pair<char16_t,           literal<'c','h','a','r','1','6','_','t'>>,
    map_pair<char32_t,           literal<'c','h','a','r','3','2','_','t'>>,
    map_pair<float,              literal<'f','l','o','a','t'>>,
    map_pair<double,             literal<'d','o','u','b','l','e'>>,
    map_pair<long double,        literal<'l','o','n','g',' ','d','o','u','b','l','e'>>,
    map_pair<std::nullptr_t,     literal<':',':','s','t','d',':',':','n','u','l','l','p','t','r','_','t'>>> fundamental_types;

template <typename L, typename R, bool b> struct type_name_parts
{
    typedef L left;
    typedef R right;
    static constexpr bool right_last = b;
};

template <typename T, typename M> struct derive_name_parts;

template <typename T, typename M = fundamental_types> struct type_name
    : concat<typename derive_name_parts<T, M>::left, typename derive_name_parts<T, M>::right> {};

template <typename P, typename S> struct derive_left
    : type_name_parts<
        concat<typename P::left, std::conditional<P::right_last, literal<'('>, literal<>>, S>,
        concat<std::conditional<P::right_last, literal<')'>, literal<>>, typename P::right>,
        false> {};

template <typename P, typename S> struct derive_right
    : type_name_parts<typename P::left, concat<S, typename P::right>, true> {};

template <typename M, typename...> struct pretty_args;
template <typename M> struct pretty_args<M>
    : literal<> {};
template <typename M, typename T> struct pretty_args<M, T>
    : type_name<T, M> {};
template <typename M, typename T, typename... Args> struct pretty_args<M, T, Args...>
    : concat<pretty_args<M, T>,literal<','>, pretty_args<M, Args...>> {};

template <typename T, typename M> struct derive_name_parts
    : type_name_parts<decltype(lookup(std::declval<tag<T>>(),std::declval<M>())), literal<>, false> {};

template <typename T, typename M> struct derive_name_parts<const T, M>
    : derive_left<derive_name_parts<T, M>, literal<' ','c','o','n','s','t'>> {};
template <typename T, typename M> struct derive_name_parts<volatile T, M>
    : derive_left<derive_name_parts<T, M>, literal<' ','v','o','l','a','t','i','l','e'>> {};
template <typename T, typename M> struct derive_name_parts<const volatile T, M>
    : derive_left<derive_name_parts<T, M>, literal<' ','c','o','n','s','t',' ','v','o','l','a','t','i','l','e'>> {};
template <typename T, typename M> struct derive_name_parts<T*, M>
    : derive_left<derive_name_parts<T, M>, literal<'*'>> {};
template <typename T, typename M> struct derive_name_parts<T&, M>
    : derive_left<derive_name_parts<T, M>, literal<'&'>> {};
template <typename T, typename M> struct derive_name_parts<T&&, M>
    : derive_left<derive_name_parts<T, M>, literal<'&','&'>> {};
template <typename T, typename M, std::size_t N> struct derive_name_parts<T[N], M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'['>,N_to_literal<N>,literal<']'>>> {};
template <typename T, typename M> struct derive_name_parts<T[], M>
    : derive_right<derive_name_parts<T, M>, literal<'[',']'>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...), M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','v','o','l','a','t','i','l','e'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t',' ','v','o','l','a','t','i','l','e'>>> {};
#ifdef NO_BROKEN_REF_QUALIFIER
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) &, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const &, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile &, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','v','o','l','a','t','i','l','e','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile &, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t',' ','v','o','l','a','t','i','l','e','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) &&, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','&','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const &&, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t','&','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile &&, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','v','o','l','a','t','i','l','e','&','&'>>> {};
template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile &&, M>
    : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')','c','o','n','s','t',' ','v','o','l','a','t','i','l','e','&','&'>>> {};
#endif
template <typename T, typename M, typename C> struct derive_name_parts<T C::*, M>
    : derive_left<derive_name_parts<T, M>, concat<std::conditional<derive_name_parts<T, M>::right_last,literal<>,literal<' '>>, type_name<C, M>, literal<':',':','*'>>> {};

int main()
{
    struct Foo;
    std::cout << type_name<int>::type::str << '\n';
    std::cout << type_name<int const>::type::str << '\n';
    std::cout << type_name<int*>::type::str << '\n';
    std::cout << type_name<int&&>::type::str << '\n';
    std::cout << type_name<int[]>::type::str << '\n';
    std::cout << type_name<int(void)>::type::str << '\n';
    std::cout << type_name<int(*)[12345]>::type::str << '\n';
    std::cout << type_name<void(int)>::type::str << '\n';
    std::cout << type_name<int&(int*, char)>::type::str << '\n';
    std::cout << type_name<int&(int*, char, int&(*&)(long,long long))>::type::str << '\n';
    std::cout << type_name<Foo>::type::str << '\n';
    std::cout << type_name<int Foo::*>::type::str << '\n';
    std::cout << type_name<int (Foo::*)()>::type::str << '\n';
    std::cout << type_name<int (Foo::*)(int, char)const volatile>::type::str << '\n';

    typedef type_map<
        fundamental_types,
        map_pair<Foo, literal<'F','o','o'>>,
        map_pair<std::string, literal<':',':','s','t','d',':',':','s','t','r','i','n','g'>>> more_types;
    std::cout << type_name<Foo, more_types>::type::str << '\n';
    std::cout << type_name<int Foo::*, more_types>::type::str << '\n';
    std::cout << type_name<int (Foo::*)(), more_types>::type::str << '\n';
#ifdef NO_BROKEN_REF_QUALIFIER
    std::cout << type_name<int (Foo::*)()&, more_types>::type::str << '\n';
#endif
    std::cout << type_name<std::string (Foo::*)(int, char)const volatile, more_types>::type::str << '\n';
}