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

后端 未结 28 2247
逝去的感伤
逝去的感伤 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条回答
  •  Happy的楠姐
    2020-11-22 17:30

    This gist provides a simple mapping based on C++ variadic templates.

    This is a C++17-simplified version of the type-based map from the gist:

    #include  // http://stackoverflow.com/q/24520781
    
    template
    struct map {
      static constexpr typename KeyValue::key_t get(const char* val) noexcept {
        if constexpr (sizeof...(RestOfKeyValues)==0)  // C++17 if constexpr
          return KeyValue::key; // Returns last element
        else {
          static_assert(KeyValue::val != nullptr,
                      "Only last element may have null name");
          return strcmp(val, KeyValue::val()) 
                ? map::get(val) : KeyValue::key;
        }
      }
      static constexpr const char* get(typename KeyValue::key_t key) noexcept {
        if constexpr (sizeof...(RestOfKeyValues)==0)
          return (KeyValue::val != nullptr) && (key == KeyValue::key)
                ? KeyValue::val() : "";
        else
          return (key == KeyValue::key) 
                ? KeyValue::val() : map::get(key);
      }
    };
    
    template
    class names {
      typedef map Map;
    public:
      static constexpr Enum get(const char* nam) noexcept {
        return Map::get(nam);
      }
      static constexpr const char* get(Enum key) noexcept {
        return Map::get(key);
      }
    };
    

    An example usage:

    enum class fasion {
        fancy,
        classic,
        sporty,
        emo,
        __last__ = emo,
        __unknown__ = -1
    };
    
    #define NAME(s) static inline constexpr const char* s() noexcept {return #s;}
    namespace name {
        NAME(fancy)
        NAME(classic)
        NAME(sporty)
        NAME(emo)
    }
    
    template  // C++17 template
    struct _ {
        typedef decltype(K) key_t;
        typedef decltype(V) name_t;
        static constexpr key_t  key = K; // enum id value
        static constexpr name_t val = V; // enum id name
    };
    
    typedef names,
        _,
        _,
        _,
        _
    > fasion_names;
    

    The map can be used in both directions:

    • fasion_names::get(fasion::emo)
    • fasion_names::get("emo")

    This example is available on godbolt.org

    int main ()
    {
      constexpr auto str = fasion_names::get(fasion::emo);
      constexpr auto fsn = fasion_names::get(str);
      return (int) fsn;
    }
    

    Result from gcc-7 -std=c++1z -Ofast -S

    main:
            mov     eax, 3
            ret
    

提交回复
热议问题