#ifndef BOOST_PP_IS_ITERATING /////////////////////////////////////////////////////////////////////////////// /// \file make.hpp /// Contains definition of the make<> 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_MAKE_HPP_EAN_12_02_2007 #define BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_2007 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace proto { namespace detail { template struct is_applyable : mpl::and_, is_transform > {}; template::value> struct nested_type { typedef typename T::type type; }; template struct nested_type { typedef T type; }; template struct nested_type_if { typedef T type; static bool const applied = false; }; template struct nested_type_if : nested_type { static bool const applied = true; }; template< typename R , typename Expr, typename State, typename Data BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(long Arity = mpl::aux::template_arity::value) > struct make_ { typedef R type; static bool const applied = false; }; template< typename R , typename Expr, typename State, typename Data , bool IsApplyable = is_applyable::value > struct make_if_ : make_ {}; template struct make_if_ : uncvref::template impl::result_type> { static bool const applied = true; }; #if BOOST_WORKAROUND(__GNUC__, == 3) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) // work around GCC bug template struct make_if_, Expr, State, Data, false> { typedef proto::expr type; static bool const applied = false; }; // work around GCC bug template struct make_if_, Expr, State, Data, false> { typedef proto::basic_expr type; static bool const applied = false; }; #endif template::value> struct construct_ { typedef Type result_type; Type operator ()() const { return Type(); } #define TMP(Z, N, DATA) \ template \ Type operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) const \ { \ return Type(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), TMP, ~) #undef TMP }; template struct construct_ { typedef Type result_type; Type operator ()() const { return Type(); } #define TMP(Z, N, DATA) \ template \ Type operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) const \ { \ Type that = {BOOST_PP_ENUM_PARAMS_Z(Z, N, a)}; \ return that; \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), TMP, ~) #undef TMP }; #define TMP(Z, N, DATA) \ template \ Type construct(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) \ { \ return construct_()(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \ } BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, TMP, ~) #undef TMP } /// \brief A PrimitiveTransform which prevents another PrimitiveTransform /// from being applied in an \c ObjectTransform. /// /// When building higher order transforms with make\<\> or /// lazy\<\>, you sometimes would like to build types that /// are parameterized with Proto transforms. In such lambda-style /// transforms, Proto will unhelpfully find all nested transforms /// and apply them, even if you don't want them to be applied. Consider /// the following transform, which will replace the \c _ in /// Bar<_>() with proto::terminal\::type: /// /// \code /// template /// struct Bar /// {}; /// /// struct Foo /// : proto::when<_, Bar<_>() > /// {}; /// /// proto::terminal::type i = {0}; /// /// int main() /// { /// Foo()(i); /// std::cout << typeid(Foo()(i)).name() << std::endl; /// } /// \endcode /// /// If you actually wanted to default-construct an object of type /// Bar\<_\>, you would have to protect the \c _ to prevent /// it from being applied. You can use proto::protect\<\> /// as follows: /// /// \code /// // OK: replace anything with Bar<_>() /// struct Foo /// : proto::when<_, Bar >() > /// {}; /// \endcode template struct protect : transform > { template struct impl { typedef PrimitiveTransform result_type; }; }; /// \brief A PrimitiveTransform which computes a type by evaluating any /// nested transforms and then constructs an object of that type. /// /// The make\<\> transform checks to see if \c Object is a template. /// If it is, the template type is disassembled to find nested transforms. /// Proto considers the following types to represent transforms: /// /// \li Function types /// \li Function pointer types /// \li Types for which proto::is_callable\< type \>::value is \c true /// /// boost::result_of\ \>(Expr, State, Data)\>::type /// is evaluated as follows. For each \c X in X0,X1,..., do: /// /// \li If \c X is a template like U\, then let X' /// be boost::result_of\ \>(Expr, State, Data)\>::type /// (which evaluates this procedure recursively). Note whether any /// substitutions took place during this operation. /// \li Otherwise, if \c X is a transform, then let X' be /// boost::result_of\(Expr, State, Data)\>::type. /// Note that a substitution took place. /// \li Otherwise, let X' be \c X, and note that no substitution /// took place. /// \li If any substitutions took place in any of the above steps and /// T\ has a nested ::type typedef, /// the result type is T\::type. /// \li Otherwise, the result type is T\. /// /// Note that when\<\> is implemented in terms of call\<\> /// and make\<\>, so the above procedure is evaluated recursively. template struct make : transform > { template struct impl : transform_impl { typedef typename detail::make_if_::type result_type; /// \return result_type() result_type operator ()( typename impl::expr_param , typename impl::state_param , typename impl::data_param ) const { return result_type(); } }; }; #define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PROTO_MAX_ARITY, )) #include BOOST_PP_ITERATE() /// INTERNAL ONLY /// template struct is_callable > : mpl::true_ {}; /// INTERNAL ONLY /// template struct is_callable > : mpl::true_ {}; }} #endif #else #define N BOOST_PP_ITERATION() namespace detail { #if N > 0 #define TMP0(Z, M, DATA) make_if_ #define TMP1(Z, M, DATA) typename TMP0(Z, M, DATA) ::type #define TMP2(Z, M, DATA) TMP0(Z, M, DATA) ::applied || template< template class R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_< R , Expr, State, Data BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N) > : nested_type_if, (BOOST_PP_REPEAT(N, TMP2, ~) false)> {}; template< template class R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_< noinvoke > , Expr, State, Data BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(1) > { typedef R type; static bool const applied = true; }; #undef TMP0 #undef TMP1 #undef TMP2 #endif template struct is_applyable : mpl::true_ {}; template struct is_applyable : mpl::true_ {}; template struct construct_, true> { typedef proto::expr result_type; template result_type operator ()(BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_MAX(N, 1), A, &a)) const { return result_type::make(BOOST_PP_ENUM_PARAMS(BOOST_PP_MAX(N, 1), a)); } }; template struct construct_, true> { typedef proto::basic_expr result_type; template result_type operator ()(BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_MAX(N, 1), A, &a)) const { return result_type::make(BOOST_PP_ENUM_PARAMS(BOOST_PP_MAX(N, 1), a)); } }; } /// \brief A PrimitiveTransform which computes a type by evaluating any /// nested transforms and then constructs an object of that type with the /// current expression, state and data, transformed according /// to \c A0 through \c AN. template struct make : transform > { template struct impl : transform_impl { /// \brief boost::result_of\(Expr, State, Data)\>::type typedef typename detail::make_if_::type result_type; /// Let \c ax be when\<_, Ax\>()(e, s, d) /// for each \c x in [0,N]. /// Return result_type(a0, a1,... aN). /// /// \param e The current expression /// \param s The current state /// \param d An arbitrary data result_type operator ()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { proto::detail::ignore_unused(e); proto::detail::ignore_unused(s); proto::detail::ignore_unused(d); return detail::construct( #define TMP(Z, M, DATA) \ detail::as_lvalue( \ typename when<_, BOOST_PP_CAT(A, M)> \ ::template impl()(e, s, d) \ ) BOOST_PP_ENUM(N, TMP, DATA) #undef TMP ); } }; }; #if BOOST_WORKAROUND(__GNUC__, == 3) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) // work around GCC bug template struct make(BOOST_PP_ENUM_PARAMS(N, A))> : transform(BOOST_PP_ENUM_PARAMS(N, A))> > { template struct impl : transform_impl { typedef proto::expr result_type; result_type operator ()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { return proto::expr::make( #define TMP(Z, M, DATA) \ detail::as_lvalue( \ typename when<_, BOOST_PP_CAT(A, M)> \ ::template impl()(e, s, d) \ ) BOOST_PP_ENUM(N, TMP, DATA) #undef TMP ); } }; }; template struct make(BOOST_PP_ENUM_PARAMS(N, A))> : transform(BOOST_PP_ENUM_PARAMS(N, A))> > { template struct impl : transform_impl { typedef proto::basic_expr result_type; result_type operator ()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { return proto::basic_expr::make( #define TMP(Z, M, DATA) \ detail::as_lvalue( \ typename when<_, BOOST_PP_CAT(A, M)> \ ::template impl()(e, s, d) \ ) BOOST_PP_ENUM(N, TMP, DATA) #undef TMP ); } }; }; #endif #undef N #endif