Phoenix v3で遊ぶ

日記を書かないと死ぬらしい(ソース不明)ので書きましょう。
Phoenix v3がtrunkにあるということで、前に作ったコードを修正しながら遊んでみました。そういえば前は確かapply作ろうとしたらbindになったとか言いましたが、よく考えたらやっぱりapplyでした。applyにプレースホルダ組み合わせたらbind(apply(), f, a, b…) と似たようなものですね。
というか、Phoenixの関数オブジェクトfはbind(f, …)と同じようなもんだと思えばややこしくない。

#include <boost/config.hpp>

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

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

#if AVAILABLE_0X_FEATURE
# include <utility>
# include <type_traits>
#else
# include <boost/utility/result_of.hpp>
# include <boost/type_traits/remove_reference.hpp>

# include <boost/preprocessor/arithmetic/inc.hpp>
# include <boost/preprocessor/facilities/intercept.hpp>
# include <boost/preprocessor/facilities/expand.hpp>
# include <boost/preprocessor/repetition/enum_params.hpp>
# include <boost/preprocessor/repetition/enum_shifted_params.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>
# include <boost/preprocessor/seq/for_each_i.hpp>
# include <boost/preprocessor/tuple/rem.hpp>
#endif

namespace bst = boost;

#if AVAILABLE_0X_FEATURE

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

#else

#define DEF_SPECIALIZED_NESTED_RESULT(z, n, data) \
template<typename This, BOOST_PP_ENUM_PARAMS_Z(z, n, typename T)> \
struct result<This(BOOST_PP_ENUM_PARAMS_Z(z, n, T))> { \
typedef typename \
bst::result_of< \
typename bst::remove_reference<T0>::type \
(BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, T))>::type \
type; \
};

#define DEF_APPLY_OVERLOADS_OP(z, n, data) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(DEF_APPLY_OVERLOADS, \
(((z, n))) BOOST_PP_REPEAT_ ## z(n, MAKE_CONST_SEQ, ~))

#define DEF_APPLY_OVERLOADS(r, seq) \
DEF_APPLY_OVERLOADS_I( \
r, \
BOOST_PP_EXPAND(BOOST_PP_TUPLE_REM(2) BOOST_PP_SEQ_HEAD(seq)), \
BOOST_PP_SEQ_TAIL(seq))
#define DEF_APPLY_OVERLOADS_I(r, zn, seq) DEF_APPLY_OVERLOADS_II(r, zn, seq)
#define DEF_APPLY_OVERLOADS_II(r, z, n, seq) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename T)> \
typename result<apply_t( \
BOOST_PP_SEQ_FOR_EACH_I_R(r, PARAMS_M, \
BOOST_PP_INTERCEPT, seq))>::type \
operator()(BOOST_PP_SEQ_FOR_EACH_I_R(r, PARAMS_M, p, seq)) const \
{ \
return p0(BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, p)); \
}

#define PARAMS_M(r, data, i, elem) \
BOOST_PP_COMMA_IF(i) T ## i elem & data ## i

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

struct apply_t {
template<typename>
struct result;
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PHOENIX_LIMIT), DEF_SPECIALIZED_NESTED_RESULT, ~)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PHOENIX_LIMIT), DEF_APPLY_OVERLOADS_OP, ~)
};

#endif

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

p3::function<apply_t> const apply;

template<typename Sig>
struct fptr_adapt_t;

template<typename R, typename A0, typename A1>
struct fptr_adapt_t<R(A0, A1)> {
typedef R result_type;
R operator()(A0 a0, A1 a1) const {
return f(a0, a1);
}
fptr_adapt_t(R (*f)(A0, A1)) : f(f) {}
R (*f)(A0, A1);
};

int f(int x, int y) {return x * y;}

template<typename F>
fptr_adapt_t<F> adapt_function(F * const & f) { return fptr_adapt_t<F>(f); }

p3::function<fptr_adapt_t<int(int, int)> > const ff(adapt_function(&f));

int main () {
using std::cout;
using namespace p3;

int n = 42;

cout << ::apply(_1, n, _2)(&f, 2) << '\n';

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

cout << ff(_1, 2)(3) << '\n';
cout << ff(1, 2)() << '\n';
cout << ff(_1, apply(_2, 3, _3))(2, ff(_1, _2), 4) << '\n';
return 0;
}