Spirit.Phoenix に apply がなかったので作ろうと思ったら bind ができたでござる

名前は apply だけど bind だよ。ちなみに boost::phoenix::bind よりすごい点は、 bind の第一引数を placeholder にできるところ。
あとC++03とC++0xの両方の場合で作ったけど、C++0xおいしいです (^q^)

#include <boost/config.hpp>

#if defined(BOOST_HAS_TR1_UTILITY) && !defined(BOOST_NO_VARIADIC_TEMPLATES) && !defined(BOOST_NO_DECLTYPE) && !defined(BOOST_NO_RVALUE_REFERENCES)
# define APPLY_IMPL_BY_0X_FEATURE 1
#else
# define APPLY_IMPL_BY_0X_FEATURE 0
#endif

#include <boost/spirit/home/phoenix/core.hpp>
#include <boost/spirit/home/phoenix/operator.hpp>
#include <boost/spirit/home/phoenix/scope.hpp>
#include <boost/spirit/home/phoenix/function.hpp>
#include <boost/spirit/home/phoenix/statement.hpp>
#include <boost/spirit/home/phoenix/bind.hpp>
#include <boost/ref.hpp>
#include <iostream>
#include <string>

#if APPLY_IMPL_BY_0X_FEATURE
# include <utility>
#else
# include <boost/mpl/assert.hpp>
# include <boost/mpl/begin_end.hpp>
# include <boost/mpl/find.hpp>
# include <boost/mpl/fold.hpp>
# include <boost/mpl/placeholders.hpp>
# include <boost/mpl/transform_view.hpp>
# include <boost/mpl/vector.hpp>
# include <boost/mpl/void.hpp>
# include <boost/function_types/function_type.hpp>
# include <boost/utility/result_of.hpp>

# include <boost/preprocessor/arithmetic/inc.hpp>
# include <boost/preprocessor/comparison/greater.hpp>
# include <boost/preprocessor/facilities/intercept.hpp>
# include <boost/preprocessor/repetition/enum_params.hpp>
# include <boost/preprocessor/repetition/enum_shifted_params.hpp>
# include <boost/preprocessor/repetition/enum_shifted_binary_params.hpp>
# include <boost/preprocessor/repetition/for.hpp>
# include <boost/preprocessor/repetition/repeat.hpp>
# include <boost/preprocessor/repetition/repeat_from_to.hpp>
# include <boost/preprocessor/seq/seq.hpp>
# include <boost/preprocessor/seq/for_each_product.hpp>
#endif

namespace bst = boost;

#if APPLY_IMPL_BY_0X_FEATURE

template<typename T>
T value();

struct apply_t {
template<typename F, typename ...AS>
struct result {
typedef decltype(value<F>()(value<AS>()...)) type;
};
template<typename F, typename ...AS>
typename result<F &&, AS &&...>::type
operator()(F && f, AS && ...as) const {
return std::forward<F>(f)(std::forward<AS>(as)...);
}
};

#else

namespace mpl = bst::mpl;

template<typename Seq, typename T>
struct take : public
mpl::iterator_range<typename mpl::begin<Seq>::type,
typename mpl::find<Seq, T>::type>
{};

#define DEF_APPLY_OVERLOADS_OP(z, n, data) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(DEF_APPLY_OVERLOADS, \
)((n))( BOOST_PP_REPEAT(n, MAKE_CONST_SEQ, _))

#define DEF_APPLY_OVERLOADS(r, seq) \
DEF_APPLY_OVERLOADS_I(BOOST_PP_SEQ_HEAD(seq), BOOST_PP_SEQ_TAIL(seq))
#define DEF_APPLY_OVERLOADS_I(n, seq) \
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
typename result<BOOST_PP_ENUM_PARAMS(n, T)>::type \
operator()(BOOST_PP_FOR((n, 0, seq), \
PARAMS_P, \
PARAMS_OP, \
PARAMS_M)) const \
{ \
return param0(BOOST_PP_ENUM_SHIFTED_PARAMS(n, param)); \
}

#define PARAMS_P(r, state) PARAMS_P_I state
#define PARAMS_P_I(n, i, seq) BOOST_PP_GREATER(n, i)

#define PARAMS_OP(r, state) PARAMS_OP_I state
#define PARAMS_OP_I(n, i, seq) (n, BOOST_PP_INC(i), BOOST_PP_SEQ_TAIL(seq))

#define PARAMS_M(r, state) PARAMS_M_I state
#define PARAMS_M_I(n, i, seq) \
BOOST_PP_COMMA_IF(i) T ## i BOOST_PP_SEQ_HEAD(seq) & param ## i

#define MAKE_CONST_SEQ(z, n, _) )(()(const))(

struct apply_t {
template<typename T0,
BOOST_PP_ENUM_SHIFTED_BINARY_PARAMS(
PHOENIX_LIMIT,
typename T,
= mpl::void_ BOOST_PP_INTERCEPT)>
struct result {
private:
typedef mpl::vector<BOOST_PP_ENUM_PARAMS(PHOENIX_LIMIT, T)> vec;
public:
typedef typename
bst::result_of<typename
bst::function_types::function_type<typename
take<mpl::transform_view<vec,
bst::unwrap_reference<mpl::_> >,
mpl::void_>::type>::type>::type type;
};
BOOST_PP_REPEAT_FROM_TO(1, PHOENIX_LIMIT, DEF_APPLY_OVERLOADS_OP, _)
};

#endif

namespace p2 {
using namespace bst::phoenix;
using namespace bst::phoenix::arg_names;
using namespace bst::phoenix::local_names;
}

p2::function<apply_t> const apply;

int f(int x, int y) {return x * y;}
int main () {
using std::cout;
using namespace p2;

int n = 42;

cout << apply(_1, n, _2)(bst::cref(&f), bst::cref(2)) << '\n';
// cout << bind(_1, n, _2)(bst::cref(&f)) << '\n'; // これはできない

let (_a = _1) [cout << apply(_a, _2, _3) << '\n'](bst::cref(&f), n, bst::cref(2));

return 0;
}

これはさすがにタイムアウトhttp://ideone.com/YnxoTX5