#include <iostream>
#include <string>

template <typename>
struct typeinfo;

#define DEFINE_TYPEINFO_0(t, v) \
        template <> \
        struct typeinfo<t> \
        { \
                static std::string name() { return v; } \
        };

#define DEFINE_TYPEINFO_1(t, v) \
        template <typename T> \
        struct typeinfo<t> \
        { \
                static std::string name() { return v; } \
        };

#define TYPEINFO(x) typeinfo<x>::name()

DEFINE_TYPEINFO_0(int, "int")
DEFINE_TYPEINFO_0(float, "float")

DEFINE_TYPEINFO_1(T*, TYPEINFO(T) + "*")

namespace foo
{
        struct bar
        {};
}

DEFINE_TYPEINFO_0(foo::bar, "foo::bar")

int main()
{
        std::cout << TYPEINFO(int) << '\n';
        std::cout << TYPEINFO(float*) << '\n';
        std::cout << TYPEINFO(foo::bar) << '\n';
}