enum to string in modern C++11 / C++14 / C++17 and future C++20

后端 未结 28 2216
逝去的感伤
逝去的感伤 2020-11-22 16:57

Contrary to all other similar questions, this question is about using the new C++ features.

  • 2008 c Is there a simple way to convert C++ enum to string?
  • <
28条回答
  •  醉梦人生
    2020-11-22 17:36

    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.

提交回复
热议问题