#ifndef BOOST_PP_IS_ITERATING /////////////////////////////////////////////////////////////////////////////// /// \file call.hpp /// Contains definition of the call<> transform. // // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007 #define BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace proto { namespace transform { namespace detail { using proto::detail::uncv; using proto::detail::as_lvalue; using proto::detail::dont_care; typedef char (&yes_type)[2]; typedef char no_type; struct private_type_ { private_type_ const &operator ,(int) const; }; template yes_type check_fun_arity(T const &); no_type check_fun_arity(private_type_ const &); template struct callable0_wrap : Fun { callable0_wrap(); typedef private_type_ const &(*pfun0)(); operator pfun0() const; }; template struct callable1_wrap : Fun { callable1_wrap(); typedef private_type_ const &(*pfun1)(dont_care); operator pfun1() const; }; template struct callable2_wrap : Fun { callable2_wrap(); typedef private_type_ const &(*pfun2)(dont_care, dont_care); operator pfun2() const; }; template struct arity0 { static callable0_wrap &fun; static int const value = sizeof(yes_type) == sizeof(check_fun_arity((fun(), 0))) ? 0 : 3; }; template struct arity1 { static callable1_wrap &fun; static A0 &a0; static int const value = sizeof(yes_type) == sizeof(check_fun_arity((fun(a0), 0))) ? 1 : 3; }; template struct arity2 { static callable2_wrap &fun; static A0 &a0; static A1 &a1; static int const value = sizeof(yes_type) == sizeof(check_fun_arity((fun(a0, a1), 0))) ? 2 : 3; }; template struct call3 { typedef typename boost::result_of::type type; template static type call(Expr2 &expr, State2 &state, Visitor2 &visitor) { Fun f; return f(expr, state, visitor); } }; template::value> struct call0 : call3 {}; template struct call0 { typedef typename boost::result_of::type type; template static type call(Expr2 &, State2 &, Visitor2 &) { Fun f; return f(); } }; template::value> struct call1 : call3 {}; template struct call1 { typedef typename boost::result_of::type type; template static type call(Expr2 &expr, State2 &, Visitor2 &) { Fun f; return f(expr); } }; template::value> struct call2 : call3 {}; template struct call2 { typedef typename boost::result_of::type type; template static type call(Expr2 &expr, State2 &state, Visitor2 &) { Fun f; return f(expr, state); } }; } // namespace detail /// \brief Wrap \c PrimitiveTransform so that when\<\> knows /// it is callable. Requires that the parameter is actually a /// PrimitiveTransform. /// /// This form of call\<\> is useful for annotating an /// arbitrary PrimitiveTransform as callable when using it with /// when\<\>. Consider the following transform, which /// is parameterized with another transform. /// /// \code /// template /// struct Foo /// : when< /// posit /// , Grammar(_arg) // May or may not work. /// > /// {}; /// \endcode /// /// The problem with the above is that when\<\> may or /// may not recognize \c Grammar as callable, depending on how /// \c Grammar is implemented. (See is_callable\<\> for /// a discussion of this issue.) The above code can guard against /// the issue by wrapping \c Grammar in call\<\>, such /// as: /// /// \code /// template /// struct Foo /// : when< /// posit /// , call(_arg) // OK, this works /// > /// {}; /// \endcode /// /// The above could also have been written as: /// /// \code /// template /// struct Foo /// : when< /// posit /// , call // OK, this works, too /// > /// {}; /// \endcode template struct call : PrimitiveTransform { BOOST_PROTO_CALLABLE() }; /// \brief Either call the PolymorphicFunctionObject with 0 /// arguments, or invoke the PrimitiveTransform with 3 /// arguments. template struct call : proto::callable { template struct result; template struct result { /// If \c Fun is a nullary PolymorphicFunctionObject, \c type is a typedef /// for boost::result_of\::::type. Otherwise, it is /// a typedef for boost::result_of\::::type. typedef typename detail::call0< Fun , Expr , State , Visitor >::type type; }; /// Either call the PolymorphicFunctionObject \c Fun with 0 arguments; or /// invoke the PrimitiveTransform \c Fun with 3 arguments: the current /// expression, state, and visitor. /// /// If \c Fun is a nullary PolymorphicFunctionObject, return Fun()(). /// Otherwise, return Fun()(expr, state, visitor). /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { typedef detail::call0< Fun , Expr , State , Visitor > impl; return impl::call(expr, state, visitor); } }; /// \brief Either call the PolymorphicFunctionObject with 1 /// argument, or invoke the PrimitiveTransform with 3 /// arguments. template struct call : proto::callable { template struct result; template struct result { /// Let \c x be when\<_, A0\>()(expr, state, visitor) and \c X /// be the type of \c x. /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, /// then \c type is a typedef for boost::result_of\::::type. /// Otherwise, it is a typedef for boost::result_of\::::type. typedef typename detail::call1< Fun , typename when<_, A0>::template result::type , State , Visitor >::type type; }; /// Either call the PolymorphicFunctionObject with 1 argument: /// the result of applying the \c A0 transform; or /// invoke the PrimitiveTransform with 3 arguments: /// result of applying the \c A0 transform, the state, and the /// visitor. /// /// Let \c x be when\<_, A0\>()(expr, state, visitor). /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, /// then return Fun()(x). Otherwise, return /// Fun()(x, state, visitor). /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { typedef detail::call1< Fun , typename when<_, A0>::template result::type , State , Visitor > impl; return impl::call( detail::as_lvalue(when<_, A0>()(expr, state, visitor)) , state , visitor ); } }; /// \brief Either call the PolymorphicFunctionObject with 2 /// arguments, or invoke the PrimitiveTransform with 3 /// arguments. template struct call : proto::callable { template struct result; template struct result { /// Let \c x be when\<_, A0\>()(expr, state, visitor) and \c X /// be the type of \c x. /// Let \c y be when\<_, A1\>()(expr, state, visitor) and \c Y /// be the type of \c y. /// If \c Fun is a binary PolymorphicFunction object that accepts \c x /// and \c y, then \c type is a typedef for /// boost::result_of\::::type. Otherwise, it is /// a typedef for boost::result_of\::::type. typedef typename detail::call2< Fun , typename when<_, A0>::template result::type , typename when<_, A1>::template result::type , Visitor >::type type; }; /// Either call the PolymorphicFunctionObject with 2 arguments: /// the result of applying the \c A0 transform, and the /// result of applying the \c A1 transform; or invoke the /// PrimitiveTransform with 3 arguments: the result of applying /// the \c A0 transform, the result of applying the \c A1 /// transform, and the visitor. /// /// Let \c x be when\<_, A0\>()(expr, state, visitor). /// Let \c y be when\<_, A1\>()(expr, state, visitor). /// If \c Fun is a binary PolymorphicFunction object that accepts \c x /// and \c y, return Fun()(x, y). Otherwise, return /// Fun()(x, y, visitor). /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { typedef detail::call2< Fun , typename when<_, A0>::template result::type , typename when<_, A1>::template result::type , Visitor > impl; return impl::call( detail::as_lvalue(when<_, A0>()(expr, state, visitor)) , detail::as_lvalue(when<_, A1>()(expr, state, visitor)) , visitor ); } }; /// \brief Call the PolymorphicFunctionObject or the /// PrimitiveTransform with the current expression, state /// and visitor, transformed according to \c A0, \c A1, and /// \c A2, respectively. template struct call : proto::callable { template struct result; template struct result { typedef typename when<_, A0>::template result::type a0; typedef typename when<_, A1>::template result::type a1; typedef typename when<_, A2>::template result::type a2; typedef typename boost::result_of::type type; }; /// Let \c x be when\<_, A0\>()(expr, state, visitor). /// Let \c y be when\<_, A1\>()(expr, state, visitor). /// Let \c z be when\<_, A2\>()(expr, state, visitor). /// Return Fun()(x, y, z). /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { Fun f; return f( detail::as_lvalue(when<_, A0>()(expr, state, visitor)) , detail::as_lvalue(when<_, A1>()(expr, state, visitor)) , detail::uncv(when<_, A2>()(expr, state, visitor)) // HACK ); } }; #if BOOST_PROTO_MAX_ARITY > 3 #define BOOST_PP_ITERATION_PARAMS_1 (3, (4, BOOST_PROTO_MAX_ARITY, )) #include BOOST_PP_ITERATE() #endif } /// INTERNAL ONLY /// template struct is_callable > : mpl::true_ {}; }} #endif #else #define N BOOST_PP_ITERATION() /// \brief Call the PolymorphicFunctionObject \c Fun with the /// current expression, state and visitor, transformed according /// to \c A0 through \c AN. template struct call : proto::callable { template struct result; template struct result { #define TMP(Z, M, DATA) \ typedef \ typename when<_, BOOST_PP_CAT(A, M)> \ ::template result \ ::type \ BOOST_PP_CAT(a, M); \ /**/ BOOST_PP_REPEAT(N, TMP, ~) #undef TMP typedef typename boost::result_of< Fun(BOOST_PP_ENUM_PARAMS(N, a)) >::type type; }; /// Let \c ax be when\<_, Ax\>()(expr, state, visitor) /// for each \c x in [0,N]. /// Return Fun()(a0, a1,... aN). /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { Fun f; #define TMP(Z, M, DATA) when<_, BOOST_PP_CAT(A, M)>()(expr, state, visitor) return f(BOOST_PP_ENUM(N, TMP, ~)); #undef TMP } }; #undef N #endif