自作列挙型を作っていますが
enumから文字列への変換をめちゃスマートに扱えるように実装できたと思ったがMSVCでしかコンパイルできないコンパイラ依存になってしまった
メモ程度にコードをあげておきます
#pragma once #include<string> #include<unordered_map> #define EXPAND( x ) x #define IE_FOR_EACH_1(_macro,e1)_macro(e1) #define IE_FOR_EACH_2(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_1(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_3(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_2(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_4(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_3(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_5(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_4(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_6(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_5(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_7(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_6(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_8(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_7(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_9(_macro,e1,...) _macro(e1) EXPAND( IE_FOR_EACH_8(_macro,__VA_ARGS__) ) #define IE_FOR_EACH_10(_macro,e1,...)_macro(e1) EXPAND( IE_FOR_EACH_9(_macro,__VA_ARGS__) ) //必要次第追加 #define IE_GET_FOR_EACH(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,NAME, ...) NAME #define IE_FOR_EACH(macro,...) EXPAND(IE_GET_FOR_EACH(__VA_ARGS__,IE_FOR_EACH_10,IE_FOR_EACH_9,IE_FOR_EACH_8,IE_FOR_EACH_7,IE_FOR_EACH_6,IE_FOR_EACH_5,IE_FOR_EACH_4,IE_FOR_EACH_3,IE_FOR_EACH_2,IE_FOR_EACH_1)(macro, __VA_ARGS__)) #define IE_MAPPING_ENUM_VAL(name) \ []()\ {\ struct Check\ {\ int v=0;\ template<class... Args>\ Check(const Args& ...args)\ {\ constexpr int size = sizeof...(args);\ if constexpr(size == 1)\ {\ v = name;\ }\ if constexpr(size == 2)\ {\ int name;\ v = name;\ }\ }\ };\ if constexpr(ie::detail::NameCheck(#name))\ {\ return Check(1).v;\ }\ else\ {\ return Check(1, 2).v;\ }\ \ return 0;\ }() #define IE_MAPPING_TO_STRING(name) {IE_MAPPING_ENUM_VAL(name), ie::detail::MappingEnumString( #name )}, namespace ie { namespace detail { struct Value { constexpr Value() = default; constexpr Value(const int& other) : value(other) {} protected: int value = 0; }; constexpr bool NameCheck(const char* test) { for (int i = 0; test[i] != '\0'; ++i) { if (test[i] == '=') { return false; } } return true; } std::string MappingEnumString(const std::string& str) { return str.substr(0, str.find('=')); } } } #define INTEGER_ENUM(...)\ struct : ie::detail::Value{\ using _ENUM=enum { __VA_ARGS__ };\ using Value::Value;\ decltype(auto) operator +=(int value) { *this = this->value + value; return *this; }\ decltype(auto) operator -=(int value) { *this = this->value - value; return *this; }\ decltype(auto) operator *=(int value) { *this = this->value * value; return *this; }\ decltype(auto) operator /=(int value) { *this = this->value / value; return *this; }\ decltype(auto) operator %=(int value) { *this = this->value % value; return *this; }\ decltype(auto) operator ++() { *this = this->value + 1; return *this; }\ decltype(auto) operator --() { *this = this->value - 1; return *this; }\ decltype(auto) operator ++(int) { auto ret = *this; *this = this->value + 1; return ret; }\ decltype(auto) operator --(int) { auto ret = *this; *this = this->value - 1; return ret; }\ constexpr operator _ENUM()const{ return static_cast<_ENUM>(value); }\ std::string to_string()const\ {\ static std::unordered_map<int, std::string> map\ {\ IE_FOR_EACH(IE_MAPPING_TO_STRING, __VA_ARGS__ )\ };\ if (map.find(value) == map.end())\ {\ return "Unknown:" + std::to_string(value);\ }\ return map.at(value);\ }\ }
使い方は
using Example = INTEGER_ENUM( A, B, Default = A ); int main() { Example a = Example::Default; std::cout<<a.to_string(); //出力 A return 0; }
とやるだけで非常にシンプルです。 INTEGER_ENUMマクロが無名構造体を生成してto_string()メソッドも自動生成してくれるというものですが MSVCのラムダ内ならメンバtemplateが使えることや、templateの文法エラーのチェックタイミングなどの関係でほかのコンパイラでは使用できません