Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file call.hpp Chris@16: /// Contains definition of the call<> transform. 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_TRANSFORM_CALL_HPP_EAN_11_02_2007 Chris@16: #define BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007 Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable: 4714) // function 'xxx' marked as __forceinline not inlined Chris@16: #endif 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: Chris@16: namespace boost { namespace proto Chris@16: { Chris@16: /// \brief Wrap \c PrimitiveTransform so that when\<\> knows Chris@16: /// it is callable. Requires that the parameter is actually a Chris@16: /// PrimitiveTransform. Chris@16: /// Chris@16: /// This form of call\<\> is useful for annotating an Chris@16: /// arbitrary PrimitiveTransform as callable when using it with Chris@16: /// when\<\>. Consider the following transform, which Chris@16: /// is parameterized with another transform. Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// struct Foo Chris@16: /// : when< Chris@16: /// unary_plus Chris@16: /// , Grammar(_child) // May or may not work. Chris@16: /// > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: /// Chris@16: /// The problem with the above is that when\<\> may or Chris@16: /// may not recognize \c Grammar as callable, depending on how Chris@16: /// \c Grammar is implemented. (See is_callable\<\> for Chris@16: /// a discussion of this issue.) You can guard against Chris@16: /// the issue by wrapping \c Grammar in call\<\>, such Chris@16: /// as: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// struct Foo Chris@16: /// : when< Chris@16: /// unary_plus Chris@16: /// , call(_child) // OK, this works Chris@16: /// > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: /// Chris@16: /// The above could also have been written as: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// struct Foo Chris@16: /// : when< Chris@16: /// unary_plus Chris@16: /// , call // OK, this works, too Chris@16: /// > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: template Chris@16: struct call Chris@16: : PrimitiveTransform Chris@16: {}; Chris@16: Chris@16: /// \brief A specialization that treats function pointer Transforms as Chris@16: /// if they were function type Transforms. Chris@16: /// Chris@16: /// This specialization requires that \c Fun is actually a function type. Chris@16: /// Chris@16: /// This specialization is required for nested transforms such as Chris@16: /// call\. In C++, functions that are used as Chris@16: /// parameters to other functions automatically decay to funtion Chris@16: /// pointer types. In other words, the type T0(T1(_)) is Chris@16: /// indistinguishable from T0(T1(*)(_)). This specialization Chris@16: /// is required to handle these nested function pointer type transforms Chris@16: /// properly. Chris@16: template Chris@16: struct call Chris@16: : call Chris@16: {}; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: struct call > Chris@16: : call Chris@16: {}; Chris@16: Chris@16: /// \brief Either call the PolymorphicFunctionObject with 0 Chris@16: /// arguments, or invoke the PrimitiveTransform with 3 Chris@16: /// arguments. Chris@16: template Chris@16: struct call : transform > Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename BOOST_PROTO_RESULT_OF::type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator()( Chris@16: typename impl2::expr_param Chris@16: , typename impl2::state_param Chris@16: , typename impl2::data_param Chris@16: ) const Chris@16: { Chris@16: return Fun()(); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: struct impl2 Chris@16: : Fun::template impl Chris@16: {}; Chris@16: Chris@16: /// Either call the PolymorphicFunctionObject \c Fun with 0 arguments; or Chris@16: /// invoke the PrimitiveTransform \c Fun with 3 arguments: the current Chris@16: /// expression, state, and data. Chris@16: /// Chris@16: /// If \c Fun is a nullary PolymorphicFunctionObject, return Fun()(). Chris@16: /// Otherwise, return Fun()(e, s, d). Chris@16: /// Chris@16: /// \param e The current expression Chris@16: /// \param s The current state Chris@16: /// \param d An arbitrary data Chris@16: Chris@16: /// If \c Fun is a nullary PolymorphicFunctionObject, \c type is a typedef Chris@16: /// for boost::result_of\::type. Otherwise, it is Chris@16: /// a typedef for boost::result_of\::type. Chris@16: template Chris@16: struct impl Chris@16: : impl2::value> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: /// \brief Either call the PolymorphicFunctionObject with 1 Chris@16: /// argument, or invoke the PrimitiveTransform with 3 Chris@16: /// arguments. Chris@16: template Chris@16: struct call : transform > Chris@16: { Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename detail::poly_function_traits::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename detail::poly_function_traits::function_type()( Chris@16: detail::as_lvalue(typename when<_, A0>::template impl()(e, s, d)) Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename Fun::template impl::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename Fun::template impl()( Chris@16: typename when<_, A0>::template impl()(e, s, d) Chris@16: , s Chris@16: , d Chris@16: ); Chris@16: } Chris@16: }; Chris@16: /// Let \c x be when\<_, A0\>()(e, s, d) and \c X Chris@16: /// be the type of \c x. Chris@16: /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, Chris@16: /// then \c type is a typedef for boost::result_of\::type. Chris@16: /// Otherwise, it is a typedef for boost::result_of\::type. Chris@16: Chris@16: /// Either call the PolymorphicFunctionObject with 1 argument: Chris@16: /// the result of applying the \c A0 transform; or Chris@16: /// invoke the PrimitiveTransform with 3 arguments: Chris@16: /// result of applying the \c A0 transform, the state, and the Chris@16: /// data. Chris@16: /// Chris@16: /// Let \c x be when\<_, A0\>()(e, s, d). Chris@16: /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, Chris@16: /// then return Fun()(x). Otherwise, return Chris@16: /// Fun()(x, s, d). Chris@16: /// Chris@16: /// \param e The current expression Chris@16: /// \param s The current state Chris@16: /// \param d An arbitrary data Chris@16: template Chris@16: struct impl Chris@16: : impl2::value> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: /// \brief Either call the PolymorphicFunctionObject with 2 Chris@16: /// arguments, or invoke the PrimitiveTransform with 3 Chris@16: /// arguments. Chris@16: template Chris@16: struct call : transform > Chris@16: { Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename when<_, A1>::template impl::result_type a1; Chris@16: typedef typename detail::poly_function_traits::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename detail::poly_function_traits::function_type()( Chris@16: detail::as_lvalue(typename when<_, A0>::template impl()(e, s, d)) Chris@16: , detail::as_lvalue(typename when<_, A1>::template impl()(e, s, d)) Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename when<_, A1>::template impl::result_type a1; Chris@16: typedef typename Fun::template impl::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename Fun::template impl()( Chris@16: typename when<_, A0>::template impl()(e, s, d) Chris@16: , typename when<_, A1>::template impl()(e, s, d) Chris@16: , d Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// Let \c x be when\<_, A0\>()(e, s, d) and \c X Chris@16: /// be the type of \c x. Chris@16: /// Let \c y be when\<_, A1\>()(e, s, d) and \c Y Chris@16: /// be the type of \c y. Chris@16: /// If \c Fun is a binary PolymorphicFunction object that accepts \c x Chris@16: /// and \c y, then \c type is a typedef for Chris@16: /// boost::result_of\::type. Otherwise, it is Chris@16: /// a typedef for boost::result_of\::type. Chris@16: Chris@16: /// Either call the PolymorphicFunctionObject with 2 arguments: Chris@16: /// the result of applying the \c A0 transform, and the Chris@16: /// result of applying the \c A1 transform; or invoke the Chris@16: /// PrimitiveTransform with 3 arguments: the result of applying Chris@16: /// the \c A0 transform, the result of applying the \c A1 Chris@16: /// transform, and the data. Chris@16: /// Chris@16: /// Let \c x be when\<_, A0\>()(e, s, d). Chris@16: /// Let \c y be when\<_, A1\>()(e, s, d). Chris@16: /// If \c Fun is a binary PolymorphicFunction object that accepts \c x Chris@16: /// and \c y, return Fun()(x, y). Otherwise, return Chris@16: /// Fun()(x, y, d). Chris@16: /// Chris@16: /// \param e The current expression Chris@16: /// \param s The current state Chris@16: /// \param d An arbitrary data Chris@16: template Chris@16: struct impl Chris@16: : impl2::value> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: /// \brief Call the PolymorphicFunctionObject or the Chris@16: /// PrimitiveTransform with the current expression, state Chris@16: /// and data, transformed according to \c A0, \c A1, and Chris@16: /// \c A2, respectively. Chris@16: template Chris@16: struct call : transform > Chris@16: { Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename when<_, A1>::template impl::result_type a1; Chris@16: typedef typename when<_, A2>::template impl::result_type a2; Chris@16: typedef typename detail::poly_function_traits::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename detail::poly_function_traits::function_type()( Chris@16: detail::as_lvalue(typename when<_, A0>::template impl()(e, s, d)) Chris@16: , detail::as_lvalue(typename when<_, A1>::template impl()(e, s, d)) Chris@16: , detail::as_lvalue(typename when<_, A2>::template impl()(e, s, d)) Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct impl2 Chris@16: : transform_impl Chris@16: { Chris@16: typedef typename when<_, A0>::template impl::result_type a0; Chris@16: typedef typename when<_, A1>::template impl::result_type a1; Chris@16: typedef typename when<_, A2>::template impl::result_type a2; Chris@16: typedef typename Fun::template impl::result_type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl2::expr_param e Chris@16: , typename impl2::state_param s Chris@16: , typename impl2::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename Fun::template impl()( Chris@16: typename when<_, A0>::template impl()(e, s, d) Chris@16: , typename when<_, A1>::template impl()(e, s, d) Chris@16: , typename when<_, A2>::template impl()(e, s, d) Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// Let \c x be when\<_, A0\>()(e, s, d). Chris@16: /// Let \c y be when\<_, A1\>()(e, s, d). Chris@16: /// Let \c z be when\<_, A2\>()(e, s, d). Chris@16: /// Return Fun()(x, y, z). Chris@16: /// Chris@16: /// \param e The current expression Chris@16: /// \param s The current state Chris@16: /// \param d An arbitrary data Chris@16: Chris@16: template Chris@16: struct impl Chris@16: : impl2::value> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: #include Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_callable > Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: }} // namespace boost::proto Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif