オレオレ 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 */