Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How does magic_enum library can output enum value as string with msvc?

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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)"
);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading