#include <iostream>
using namespace std;

class static_string
{
	const char* const p_;
	const std::size_t sz_;

public:
	typedef const char* const_iterator;

	template <std::size_t N>
	constexpr static_string(const char(&a)[N]) noexcept
		: p_(a)
		, sz_(N - 1)
	{}

	constexpr static_string(const char* p, std::size_t N) noexcept
		: p_(p)
		, sz_(N)
	{}

	constexpr const char* data() const noexcept { return p_; }
	constexpr std::size_t size() const noexcept { return sz_; }

	constexpr const_iterator begin() const noexcept { return p_; }
	constexpr const_iterator end()   const noexcept { return p_ + sz_; }

	constexpr char operator[](std::size_t n) const
	{
		return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
	}
};

inline std::ostream& operator<<(std::ostream& os, static_string const& s)
{
	return os.write(s.data(), s.size());
}

/// \brief Get the name of a type
template <class T>
static_string typeName()
{
#ifdef __clang__
	static_string p = __PRETTY_FUNCTION__;
	return static_string(p.data() + 30, p.size() - 30 - 1);
#elif defined(_MSC_VER)
	static_string p = __FUNCSIG__;
	return static_string(p.data() + 37, p.size() - 37 - 7);
#endif
	
}

namespace details
{
	template <class Enum>
	struct EnumWrapper
	{
		template < Enum enu >
		static static_string name()
		{
#ifdef __clang__
			static_string p = __PRETTY_FUNCTION__;
			static_string enumType = typeName<Enum>();
			return static_string(p.data() + 73 + enumType.size(), p.size() - 73 - enumType.size() - 1);
#elif defined(_MSC_VER)
			static_string p = __FUNCSIG__;
			static_string enumType = typeName<Enum>();
			return static_string(p.data() + 57 + enumType.size(), p.size() - 57 - enumType.size() - 7);
#endif
		}
	};
}

/// \brief Get the name of an enum value
template <typename Enum, Enum enu>
static_string enumName()
{
	return details::EnumWrapper<Enum>::template name<enu>();
}

enum class Color
{
    Blue = 0,
    Yellow = 1
};


int main() 
{
	std::cout << "_" << typeName<Color>() << "_"  << std::endl;
	std::cout << "_" << enumName<Color, Color::Blue>() << "_"  << std::endl;
	return 0;
}