The magic_enum library provides way to retrieve an enum value as its name, in the form of a string.
For instance:
#include <iostream>
#include "magic_enum.hpp"
enum class Dummy : uint16_t {
first,
second,
third,
};
int main() {
std::cout << magic_enum::enum_name<Dummy::first>()
<< std::endl; // outputs "first"}
Does some can explain here how magic_enum
actually implements enum_name
with msvc?
I managed to reproduce this behavior with clang/gcc by passing the enum value to a template function and using __PRETTY_FUNCTION__
inside, for instance:
template<typename Enum_T, Enum_T Value_E> class EnumValueNameAsString
{
static constexpr std::string_view Get()
{
auto constexpr end = std::string_view(__PRETTY_FUNCTION__).find_last_of(';');
if constexpr (end == std::string_view::npos)
{
return std::string_view("Failure");
}
auto constexpr start
= std::string_view(__PRETTY_FUNCTION__).find_last_of('=', end);
if constexpr (start == std::string_view::npos)
{
return std::string_view(
"Failure");
}
// 0 <= start < end
if constexpr (end - start <= 2)
{
return std::string_view(
"Failure");
}
return std::string_view(__PRETTY_FUNCTION__).substr(start + 2, end - start - 2);
}
public:
static constexpr std::string_view Name = Get();
};
But for C++, using __FUNCSIG__
instead of __PRETTY_FUNCTION__
, I cannot achieve the expected result as __FUNCSIG__
actually is class std::basic_string_view<char,struct std::char_traits<char> > __cdecl EnumValueNameAsString<enum Dummy,0>::Get(void)
The enum value name is nowhere in the string.
>Solution :
It seems like __FUNCSIG__
only converts an enum non-type template argument to its name in the immediately enclosing function. It will leave the 0
in the struct as a 0
since that’s not the function being called.
The fix is to use the enum template argument in the static member function, or use a free function:
template<typename Enum_T, Enum_T Value_E>
constexpr std::string_view f() { return __FUNCSIG__; }
template<typename Enum_T, Enum_T Value_E>
class EnumValueNameAsString {
template<Enum_T>
static constexpr std::string_view Get() {
return __FUNCSIG__;
}
public:
static constexpr std::string_view Name = Get<Value_E>();
};
static_assert(f<Dummy, Dummy::first>() ==
"class std::basic_string_view<char,struct std::char_traits<char> > __cdecl f<enum Dummy,Dummy::first>(void)"
);
static_assert(EnumValueNameAsString <Dummy, Dummy::first>::Name ==
"class std::basic_string_view<char,struct std::char_traits<char> > __cdecl EnumValueNameAsString<enum Dummy,0>::Get<Dummy::first>(void)"
);