カリー化

まだ整理できていないがとりあえずできた。

#include <boost/type_traits/function_traits.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/utility/result_of.hpp>

namespace exist {

namespace currying_detail {

struct currying_start;

template<typename R, typename BindArg, typename Base, unsigned int rest>
struct currying_t : public Base {
typedef Base base;
using Base::apply;
template<typename F_>
struct result {
typedef currying_t<R, typename boost::function_traits<F_>::arg1_type, currying_t, rest - 1> type;
};
BindArg arg_;

template<typename A>
currying_t<R, A, currying_t, rest - 1> operator()(A a) {
return currying_t<R, A, currying_t, rest - 1>(*this, a);
}
currying_t(Base const & base, BindArg const & arg) : Base(base), arg_(arg) {}
};

template<typename R, typename BindArg, typename Base>
struct currying_t<R, BindArg, Base, 1> : public Base {
typedef R result_type;
BindArg arg_;

template<typename A>
R operator()(A a) {
return Base::template apply<currying_t, 1>(a);
}
currying_t(Base const & base, BindArg const & arg) : Base(base), arg_(arg) {}
};

template<typename R, typename F, unsigned int rest>
struct currying_t<R, currying_start, F, rest> {
template<typename F_>
struct result {
typedef currying_t<R, typename boost::function_traits<F_>::arg1_type, currying_t, rest - 1> type;
};
F f_;

template<typename A>
currying_t<R, A, currying_t, rest - 1> operator()(A a) {
return currying_t<R, A, currying_t, rest - 1>(*this, a);
}
template<typename Args, int dummy, typename A>
typename boost::enable_if_c<rest == 2 && dummy, R>::type
apply(A a) {
Args& self = static_cast<Args&>(*this);
return f_(self.arg_, a);
}
template<typename Args, int dummy, typename A>
typename boost::enable_if_c<rest == 3 && dummy, R>::type
apply(A a) {
Args& self = static_cast<Args&>(*this);
return f_(self.Args::base::arg_, self.arg_, a);
}
template<typename Args, int dummy, typename A>
typename boost::enable_if_c<rest == 4 && dummy, R>::type
apply(A a) {
Args& self = static_cast<Args&>(*this);
return f_(self.Args::base::base::arg_, self.Args::base::arg_, self.arg_, a);
}
currying_t(F f) : f_(f) {}
};

} // namespace currying_detail

template<typename R, typename F>
typename boost::enable_if_c<boost::is_function<F>::value,
currying_detail::currying_t<typename boost::function_traits<F>::result_type, currying_detail::currying_start, F*, boost::function_traits<F>::arity>
>::type
currying(F* f) {
return currying_detail::currying_t<R, currying_detail::currying_start, F*, boost::function_traits<F>::arity>(f);
}

template<typename R, unsigned int arity, typename F>
typename boost::disable_if_c<boost::is_function<F>::value,
currying_detail::currying_t<R, currying_detail::currying_start, F, arity>
>::type
currying(F const & f) {
return currying_detail::currying_t<R, currying_detail::currying_start, F, arity>(f);
}

} // namespace exist