Basic enum reflection

As basic and simple as it can be1. For a full reflection with heavy compiler torture and spending a basket of CPU cycles for it, use magic_enum or reflect-cpp or similar.

#include <cassert>
#include <cstdint>
#include <cstddef>
#include <source_location>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>

#include <cxxabi.h>
#include <cstdlib>

namespace lpt {

namespace impl {

// constexpr auto lpt::impl::name_and_val() [with E = main()::Color; E V = main::Color::eRED]
constexpr std::string_view enum_val_name(std::string_view name) noexcept 
{
    int i(name.length() - 1);
    for (i; i >=0; --i) 
    {
        if (name[i] == ' ')
        {
            break;
        }
    }

    return std::string_view(&name[i], name.length() -  1 - i); // main::Color::eRED
}

template <typename E, E V>
constexpr auto name_and_val() noexcept 
{
    static_assert(std::is_enum_v<E>, "not an enum");
    return enum_val_name(std::source_location::current().function_name());
}

template <typename E, E V>
constexpr auto enum_name() noexcept 
{
    constexpr auto name = name_and_val<E, V>();
    return std::string_view{name}; 
}

template <typename E, E V>
inline constexpr auto enum_name_v = enum_name<E, V>();

}  // namespace impl


/**
   Stringizing an enum
   \code
       #include <lpt/enum_tools.hpp>
       enum class Color { eRED=-199, eGREEN=0, eYELLOW=5 };
       std::cout << lpt::to_string<Color::eRED>();
   \endcode
 */

template <auto V>
requires (std::is_enum_v<decltype(V)>)
constexpr auto to_string() noexcept 
{
    using D = std::decay_t<decltype(V)>;
    constexpr std::string_view name = impl::enum_name_v<D, V>;
    static_assert( ! name.empty(), "enum value has no name");
    return name;
}

} //namespace lpt
Written on February 19, 2024