switchで文字列を使いたい
C++ではできないので、マクロを使ってでっち上げる。
namespace ns_switch { template<class C> const C* select(const char* str, const wchar_t* wcs) { return str; } template<> const wchar_t* select<wchar_t>(const char* str, const wchar_t* wcs) { return wcs; } template <class T, T v> struct constant { typedef T type; static const T value = v; }; template <bool flag, class T, class U> struct select_type { typedef U type; }; template <class T, class U> struct select_type<true,T,U> { typedef T type; }; template <class T, class U> struct is_same_type:ns_switch::constant<bool, false> {}; template <class T> struct is_same_type<T,T>:ns_switch::constant<bool, true> {}; #define STR2(X) #X #define STR(X) STR2(X) #define WSTR(X) CAT(L,STR(X)) #define CAT2(X,Y) X##Y #define CAT(X,Y) CAT2(X,Y) #define SIZE(X) (sizeof(X)/sizeof((X)[0])) template <class T> struct switchtype { typedef T type; }; template <class T> struct same_type { typedef T type; }; template <class CHAR> struct switchtype<CHAR*> { typedef std::basic_string<CHAR> type; }; template <class CHAR,int N> struct switchtype<const CHAR[N]> { typedef std::basic_string<CHAR> type; }; template <class CHAR,int N> struct switchtype<CHAR[N]> { typedef std::basic_string<CHAR> type; }; template <class CHAR> struct switchtype<const CHAR[]> { typedef std::basic_string<CHAR> type; }; template <class CHAR> struct switchtype<CHAR[]> { typedef std::basic_string<CHAR> type; }; #define IS_SAME(X,Y) ns_switch::is_same_type<ns_switch:: \ same_type<__typeof(X)>::type::value_type,Y>::value #define SWITCHL CAT(_SWITCHL, __LINE__) #define SWITCH(X) do { void* LABEL=0; \ const ns_switch::switchtype<__typeof(X)>::type&_(X); if(0) #define CASE(Y) COND(_== Y) #define RANGE(X,Y) COND((X)<=_&&_<=(Y)) #define MATCH(X) \ COND(boost::regex_search(_, \ boost::basic_regex<ns_switch::same_type<__typeof(_)> \ ::type::value_type> \ (ns_switch::select \ <ns_switch::select_type<IS_SAME(_,char), \ char, wchar_t \ >::type \ >(STR(X),WSTR(X))+1, \ ns_switch::select_type<IS_SAME(_,char), \ ns_switch::constant<int, SIZE(STR(X))>, \ ns_switch::constant<int, SIZE(WSTR(X))> \ >::type::value-3, \ boost::regex_constants::match_default ))) #define COND(Y) goto SWITCHL; } else if(Y) { SWITCHL: #define DEFAULT goto SWITCHL; } else { LABEL=&&SWITCHL; } \ if(0) { SWITCHL: #define ENDSWITCH else { if(LABEL) goto *LABEL; } } while(0) } // end ns_switch
使い方のサンプル↓
int main(int argc, char **argv) { for(int i = 1; i < argc; ++i){ std::cout << argv[i] << "は"; SWITCH(argv[i]) { CASE("foo") CASE("bar") std::cout << "foo 又は barです" << std::endl; break; DEFAULT std::cout << "その他の文字列" << std::endl; break; RANGE("bc","de") std::cout << "bcとdeの間" << std::endl; break; CASE("hage") std::cout << "hageです "; MATCH("age") std::cout << "ageが含まれる文字列" << std::endl; break; MATCH("^\d+$") std::cout << "数字だけからなる文字列" << std::endl; break; COND(_[0]=='a') std::cout << "aで始まる文字列" << std::endl; break; } ENDSWITCH; } return 0; }