#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 namespace boost { namespace proto { namespace detail { template struct typelist { typedef void type; }; template::value> struct nested_type { typedef typename T::type type; }; template struct nested_type { typedef T type; }; template struct nested_type_if : nested_type {}; template::value > struct make_if_; template::value) > struct make_ { typedef R type; typedef void not_applied_; }; template struct make_if_ : make_ {}; #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; typedef void not_applied_; }; // work around GCC bug template struct make_if_, Expr, State, Data, false> { typedef proto::basic_expr type; typedef void not_applied_; }; #endif // TODO could optimize this if R is a transform template struct make_if_ : uncvref::result_type> {}; 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 template struct nested_type_if< T , typelist , typename typelist< BOOST_PP_ENUM_BINARY_PARAMS(N, typename A, ::not_applied_ BOOST_PP_INTERCEPT) >::type > { typedef T type; typedef void not_applied_; }; #define TMP0(Z, M, DATA) make_if_ #define TMP1(Z, M, DATA) typename TMP0(Z, M, DATA) ::type template< template class R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_, Expr, State, Data BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N) > : nested_type_if< R , typelist > {}; template< template class R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_ >, Expr, State, Data BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N) > { typedef R type; }; #undef TMP0 #undef TMP1 #endif template< typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_if_ { typedef typename uncvref< typename when<_, R(BOOST_PP_ENUM_PARAMS(N, A))> ::template impl::result_type >::type type; }; template< typename R BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) , typename Expr, typename State, typename Data > struct make_if_ { typedef typename uncvref< typename when<_, R(BOOST_PP_ENUM_PARAMS(N, A))> ::template impl::result_type >::type type; }; 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; //typedef typename detail::make_::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