Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file callable.hpp Chris@16: /// Definintion of callable_context\<\>, an evaluation context for Chris@16: /// proto::eval() that explodes each node and calls the derived context Chris@16: /// type with the expressions constituents. If the derived context doesn't Chris@16: /// have an overload that handles this node, fall back to some other Chris@16: /// context. Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_PROTO_CONTEXT_CALLABLE_HPP_EAN_06_23_2007 Chris@16: #define BOOST_PROTO_CONTEXT_CALLABLE_HPP_EAN_06_23_2007 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // for child_c Chris@16: Chris@16: namespace boost { namespace proto Chris@16: { Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct callable_context_wrapper Chris@16: : remove_cv::type Chris@16: { Chris@16: callable_context_wrapper(); Chris@16: typedef private_type_ fun_type(...); Chris@16: operator fun_type *() const; Chris@16: private: Chris@16: callable_context_wrapper &operator =(callable_context_wrapper const &); Chris@16: }; Chris@16: Chris@16: template Chris@16: yes_type check_is_expr_handled(T const &); Chris@16: Chris@16: no_type check_is_expr_handled(private_type_ const &); Chris@16: Chris@16: template Chris@16: struct is_expr_handled; Chris@16: Chris@16: template Chris@16: struct is_expr_handled Chris@16: { Chris@16: static callable_context_wrapper &sctx_; Chris@16: static Expr &sexpr_; Chris@16: static typename Expr::proto_tag &stag_; Chris@16: Chris@16: static const bool value = Chris@16: sizeof(yes_type) == Chris@16: sizeof( Chris@16: detail::check_is_expr_handled( Chris@16: (sctx_(stag_, proto::value(sexpr_)), 0) Chris@16: ) Chris@16: ); Chris@16: Chris@16: typedef mpl::bool_ type; Chris@16: }; Chris@16: } Chris@16: Chris@16: namespace context Chris@16: { Chris@16: /// \brief A BinaryFunction that accepts a Proto expression and a Chris@16: /// callable context and calls the context with the expression tag Chris@16: /// and children as arguments, effectively fanning the expression Chris@16: /// out. Chris@16: /// Chris@16: /// callable_eval\<\> requires that \c Context is a Chris@16: /// PolymorphicFunctionObject that can be invoked with \c Expr's Chris@16: /// tag and children as expressions, as follows: Chris@16: /// Chris@16: /// \code Chris@16: /// context(Expr::proto_tag(), child_c<0>(expr), child_c<1>(expr), ...) Chris@16: /// \endcode Chris@16: template< Chris@16: typename Expr Chris@16: , typename Context Chris@16: , long Arity // = Expr::proto_arity_c Chris@16: > Chris@16: struct callable_eval Chris@16: {}; Chris@16: Chris@16: /// \brief A BinaryFunction that accepts a Proto expression and a Chris@16: /// callable context and calls the context with the expression tag Chris@16: /// and children as arguments, effectively fanning the expression Chris@16: /// out. Chris@16: /// Chris@16: /// callable_eval\<\> requires that \c Context is a Chris@16: /// PolymorphicFunctionObject that can be invoked with \c Expr's Chris@16: /// tag and children as expressions, as follows: Chris@16: /// Chris@16: /// \code Chris@16: /// context(Expr::proto_tag(), value(expr)) Chris@16: /// \endcode Chris@16: template Chris@16: struct callable_eval Chris@16: { Chris@16: typedef typename proto::result_of::value::type value_type; Chris@16: Chris@16: typedef Chris@16: typename BOOST_PROTO_RESULT_OF< Chris@16: Context(typename Expr::proto_tag, value_type) Chris@16: >::type Chris@16: result_type; Chris@16: Chris@16: /// \param expr The current expression Chris@16: /// \param context The callable evaluation context Chris@16: /// \return context(Expr::proto_tag(), value(expr)) Chris@16: result_type operator ()(Expr &expr, Context &context) const Chris@16: { Chris@16: return context(typename Expr::proto_tag(), proto::value(expr)); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// \brief An evaluation context adaptor that makes authoring a Chris@16: /// context a simple matter of writing function overloads, rather Chris@16: /// then writing template specializations. Chris@16: /// Chris@16: /// callable_context\<\> is a base class that implements Chris@16: /// the context protocol by passing fanned-out expression nodes to Chris@16: /// the derived context, making it easy to customize the handling Chris@16: /// of expression types by writing function overloads. Only those Chris@16: /// expression types needing special handling require explicit Chris@16: /// handling. All others are dispatched to a user-specified Chris@16: /// default context, \c DefaultCtx. Chris@16: /// Chris@16: /// callable_context\<\> is defined simply as: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// struct callable_context Chris@16: /// { Chris@16: /// template Chris@16: /// struct eval Chris@16: /// : mpl::if_< Chris@16: /// is_expr_handled_ // For exposition Chris@16: /// , callable_eval Chris@16: /// , typename DefaultCtx::template eval Chris@16: /// >::type Chris@16: /// {}; Chris@16: /// }; Chris@16: /// \endcode Chris@16: /// Chris@16: /// The Boolean metafunction is_expr_handled_\<\> uses Chris@16: /// metaprogramming tricks to determine whether \c Context has Chris@16: /// an overloaded function call operator that accepts the Chris@16: /// fanned-out constituents of an expression of type \c Expr. Chris@16: /// If so, the handling of the expression is dispatched to Chris@16: /// callable_eval\<\>. If not, it is dispatched to Chris@16: /// the user-specified \c DefaultCtx. Chris@16: /// Chris@16: /// Below is an example of how to use callable_context\<\>: Chris@16: /// Chris@16: /// \code Chris@16: /// // An evaluation context that increments all Chris@16: /// // integer terminals in-place. Chris@16: /// struct increment_ints Chris@16: /// : callable_context< Chris@16: /// increment_ints const // derived context Chris@16: /// , null_context const // fall-back context Chris@16: /// > Chris@16: /// { Chris@16: /// typedef void result_type; Chris@16: /// Chris@16: /// // Handle int terminals here: Chris@16: /// void operator()(proto::tag::terminal, int &i) const Chris@16: /// { Chris@16: /// ++i; Chris@16: /// } Chris@16: /// }; Chris@16: /// \endcode Chris@16: /// Chris@16: /// With \c increment_ints, we can do the following: Chris@16: /// Chris@16: /// \code Chris@16: /// literal i = 0, j = 10; Chris@16: /// proto::eval( i - j * 3.14, increment_ints() ); Chris@16: /// Chris@16: /// assert( i.get() == 1 && j.get() == 11 ); Chris@16: /// \endcode Chris@16: template< Chris@16: typename Context Chris@16: , typename DefaultCtx // = default_context Chris@16: > Chris@16: struct callable_context Chris@16: { Chris@16: /// A BinaryFunction that accepts an \c Expr and a Chris@16: /// \c Context, and either fans out the expression and passes Chris@16: /// it to the context, or else hands off the expression to Chris@16: /// \c DefaultCtx. Chris@16: /// Chris@16: /// If \c Context is a PolymorphicFunctionObject such that Chris@16: /// it can be invoked with the tag and children of \c Expr, Chris@16: /// as ctx(Expr::proto_tag(), child_c\<0\>(expr), child_c\<1\>(expr)...), Chris@16: /// then eval\ inherits from Chris@16: /// callable_eval\. Otherwise, Chris@16: /// eval\ inherits from Chris@16: /// DefaultCtx::eval\. Chris@16: template Chris@16: struct eval Chris@16: : mpl::if_c< Chris@16: detail::is_expr_handled::value Chris@16: , callable_eval Chris@16: , typename DefaultCtx::template eval Chris@16: >::type Chris@16: {}; Chris@16: }; Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: }} Chris@16: Chris@16: #endif