オレオレ switch case つくったよー
つくりはじめてからだいぶ時間が経ってしまったんですが、ぐだぐだになってきたので、暫定版って事で。
#include <iostream> #include <string> #include <boost/lexical_cast.hpp> #include <boost/lambda/lambda.hpp> #include "switch_case.hpp" namespace sc = switch_case; std::string check(int n){ return sc::switch_(n%2==0) |=sc::case_(true , sc::var(std::string("偶数"))) |=sc::case_(false, sc::var(std::string("奇数"))); } void fizz_buzz(int n){ using boost::lambda::constant; using sc::_; sc::switch_(n%3, n%5) |=sc::case_(0,0, std::cout << constant("fizz_buzz") << ",") |=sc::case_(0,_, std::cout << constant("fizz") << ",") |=sc::case_(_,0, std::cout << constant("buzz") << ",") |=sc::default_(std::cout << constant(boost::lexical_cast<std::string>(n)) << ","); } void dog(){ std::cout << "わんわんお!" << std::endl; } void cat(){ std::cout << "にゃーにゃー。" << std::endl; } void qb(){ std::cout << "僕と契約して魔法少女になってよ!!" << std::endl; } void say(std::string s){ sc::switch_(s) |=sc::case_(std::string("Dog"), &dog) |=sc::case_(std::string("Cat"), &cat) |=sc::case_(std::string("QB"), &qb); } int main(){ say("Dog"); say("Cat"); say("QB"); for( int i = 0 ; i < 10 ; i++ ){ std::cout << check(i); } std::cout << std::endl; for( int i = 1 ; i < 20 ; i++ ){ fizz_buzz(i); } return 0; }
[出力]
わんわんお! にゃーにゃー。 僕と契約して魔法少女になってよ!! 偶数奇数偶数奇数偶数奇数偶数奇数偶数奇数 1,2,fizz,4,buzz,fizz,7,8,fizz,buzz,11,fizz,13,14,fizz_buzz,16,17,fizz,19,
使い方や雰囲気なんかは上記の通り。
マッチする値と関数を渡すことで、マッチした場合に関数の評価を行います。
switch case 文の様なbreak; がないので、マッチした段階で関数を評価して、値を返します。
変数やコンスタントな値を渡す場合は、sc::var でラップする事で関数として評価されます。
case の値は、2つまで対応。
3つ以上の場合は、boost::tuple 等でラップすればいいと思います。
関数だった場合の切り分けとかが難しくて、かなりぐだぐだになってしまいました。
やはり、関数回りの処理は鬼門。
あと C++0x のラムダ式は、Boost.Result_of が対応していないので無理です。
gcc なら #define BOOST_RESULT_OF_USE_DECLTYPE を定義することで、decltype ベースの result_of になるので、C++0x lambda も使えると思います。
試してはいませんが。
C++0x 早く来いッッッ!!
[boost]
ver 1.46.1
[参照]
http://d.hatena.ne.jp/faith_and_brave/20100818/1282111093
http://d.hatena.ne.jp/faith_and_brave/20100602/1275466102
https://svn.boost.org/svn/boost/sandbox/boost/type_switch.hpp
突っ込みどころ満載の switch_case.hpp は、以下から。
[switch_case.hpp]
#ifndef _SWITCH_CASE_ #define _SWITCH_CASE_ #include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple_comparison.hpp> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/utility/result_of.hpp> namespace switch_case{ namespace detail{ template<typename F> struct result_type : boost::result_of<F()>{}; template<typename F> struct result_type<F&> : result_type<F>{}; template<typename F> struct result_type<F const&> : result_type<F>{}; struct empty_case{}; template<typename T, typename U> bool equal(const T& t, const U& u){ return t == u; } template<typename T, typename C, typename N> typename result_type<C>::type call_func(const T& src, C& case_, N& next){ return case_.equal(src) ? case_() : next.visit(src); } // 戻り値がある場合は、問答無用で最後の関数が呼ばれる template<typename T, typename C> typename boost::lazy_disable_if<boost::is_same< typename C::result_type, void >, result_type<C> >::type call_func(const T& src, C& case_, empty_case&){ return case_(); } // 戻り値がない場合は、こちらが呼ばれる template<typename T, typename C> typename boost::enable_if<boost::is_same< typename C::result_type, void >, void>::type call_func(const T& src, C& case_, empty_case&){ if( case_.equal(src) ) case_(); } template<typename CaseValueT, typename F, typename Next = empty_case> struct case_t{ typedef typename result_type<F>::type result_type; typedef Next NextT; explicit case_t(const CaseValueT& s, F func_, const Next& next_ = empty_case()) : case_value(s), func(func_), next(next_){} template<typename Next_> case_t<CaseValueT, F, Next_> operator |=(const Next_& next){ return case_t<CaseValueT, F, Next_>(case_value, func, next); } result_type operator ()(){ return static_cast<result_type>(func()); } template<typename U> result_type visit(const U& src){ return call_func(src, *this, next); } template<typename T> bool equal(const T& rhs){ return case_value == rhs; } private: CaseValueT case_value; F func; Next next; }; template<typename T> struct switche_t{ typedef T value_type; explicit switche_t(const T& value_) : value(value_){} template<typename case_t> typename case_t::result_type operator |=(case_t case_) const{ return case_.visit(value); } private: value_type value; }; // "*" の代わり struct true_{}_; template<typename T> bool operator ==(const true_&, const T&){ return true; } template<typename T> struct functionable_holder{ typedef T result_type; explicit functionable_holder(T t) : value(t){} result_type operator ()(){ return value; } result_type operator ()() const{ return value; } private: T value; }; } // namespace detail using detail::_; template<typename T> detail::functionable_holder<T&> var(T& t){ return detail::functionable_holder<T&>(t); } template<typename T> detail::functionable_holder<T const&> var(T const& t){ return detail::functionable_holder<T const&>(t); } template<typename T> detail::switche_t<T> switch_(const T& t){ return detail::switche_t<T>(t); } template<typename T, typename F> detail::case_t<T, F&> case_(const T& t, F& func){ return detail::case_t<T, F&>(t, func); } template<typename T, typename F> detail::case_t<T, const F&> case_(const T& t, const F& func){ return detail::case_t<T, const F&>(t, func); } template<typename F> detail::case_t<detail::true_, F&> default_(F& func){ return detail::case_t<detail::true_, F&>(_, func); } template<typename F> detail::case_t<detail::true_, const F&> default_(const F& func){ return detail::case_t<detail::true_, const F&>(_, func); } // 引数が2個以上の場合は、boost::tuple で保持 template<typename T1, typename T2> detail::switche_t<boost::tuple<T1, T2> > switch_(const T1& t1, const T2& t2){ return detail::switche_t<boost::tuple<T1, T2> > (boost::make_tuple(t1, t2)); } template<typename T1, typename T2, typename F> detail::case_t<boost::tuple<T1, T2>, F&> case_(const T1& t1, const T2& t2, F& func){ return detail::case_t<boost::tuple<T1, T2>, F&> (boost::make_tuple(t1, t2), func); } template<typename T1, typename T2, typename F> detail::case_t<boost::tuple<T1, T2>, const F&> case_(const T1& t1, const T2& t2, const F& func){ return detail::case_t<boost::tuple<T1, T2>, const F&> (boost::make_tuple(t1, t2), func); } } // namespace switch_case #endif /* end of include guard */