MPL でカリー化

curryN<F> で,N-ary なメタ関数クラス F をカリー化します.

#ifndef CURRY_HPP
#define CURRY_HPP

#include <boost/mpl/bind.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/protect.hpp>
#include <boost/preprocessor/arithmetic/dec.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>

template <class F>
struct curry1
  : F
{};

#define BOOST_PP_LOCAL_MACRO(n) \
template <class F> \
struct BOOST_PP_CAT(curry, n) \
{ \
    template <class A1> \
    struct apply \
    { \
        typedef \
            BOOST_PP_CAT(curry, BOOST_PP_DEC(n))< \
                boost::mpl::protect< \
                    BOOST_PP_CAT(boost::mpl::bind, n)< \
                        F, \
                        A1, \
                        BOOST_PP_ENUM_SHIFTED_PARAMS(n, boost::mpl::_) \
                    > \
                > \
            > \
        type; \
    }; \
}; \
/**/
#define BOOST_PP_LOCAL_LIMITS (2, BOOST_MPL_LIMIT_METAFUNCTION_ARITY)
#include BOOST_PP_LOCAL_ITERATE()

#endif
#include <boost/mpl/assert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/plus.hpp>
#include "curry.hpp"

using namespace boost::mpl;

struct my_plus
{
    template <class A1, class A2, class A3>
    struct apply
      : plus<A1, A2, A3>
    {};
};

typedef curry3<my_plus> curried_my_plus;

BOOST_MPL_ASSERT_RELATION(
    curried_my_plus::apply<int_<1> >::type::apply<int_<2> >::type::apply<int_<3> >::type::value,
    ==,
    6
);

bind や protect に合わせて,::type せずに使う仕様にしています.