I have been frustrated by this problem for a long time too, along with the problem of getting a type converted to string in a proper way. However, for the last problem, I was surprised by the solution explained in Is it possible to print a variable's type in standard C++?, using the idea from Can I obtain C++ type names in a constexpr way?. Using this technique, an analogous function can be constructed for getting an enum value as string:
#include
using namespace std;
class static_string
{
const char* const p_;
const std::size_t sz_;
public:
typedef const char* const_iterator;
template
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
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
struct EnumWrapper
{
template < Enum enu >
static static_string name()
{
#ifdef __clang__
static_string p = __PRETTY_FUNCTION__;
static_string enumType = typeName();
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();
return static_string(p.data() + 57 + enumType.size(), p.size() - 57 - enumType.size() - 7);
#endif
}
};
}
/// \brief Get the name of an enum value
template
static_string enumName()
{
return details::EnumWrapper::template name();
}
enum class Color
{
Blue = 0,
Yellow = 1
};
int main()
{
std::cout << "_" << typeName() << "_" << std::endl;
std::cout << "_" << enumName() << "_" << std::endl;
return 0;
}
The code above has only been tested on Clang (see https://ideone.com/je5Quv) and VS2015, but should be adaptable to other compilers by fiddling a bit with the integer constants. Of course, it still uses macros under the hood, but at least one doesn't need access to the enum implementation.