/////////////////////////////////////////////////////////////////////////////// /// \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 <boost/detail/workaround.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/facilities/intercept.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/selection/max.hpp> #include <boost/preprocessor/arithmetic/inc.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/aux_/has_type.hpp> #include <boost/proto/detail/template_arity.hpp> #include <boost/utility/result_of.hpp> #include <boost/proto/proto_fwd.hpp> #include <boost/proto/traits.hpp> #include <boost/proto/args.hpp> #include <boost/proto/transform/impl.hpp> #include <boost/proto/transform/detail/pack.hpp> #include <boost/proto/detail/as_lvalue.hpp> #include <boost/proto/detail/ignore_unused.hpp> #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined #endif namespace boost { namespace proto { namespace detail { template<typename T> struct is_applyable : mpl::and_<is_callable<T>, is_transform<T> > {}; template<typename T, bool HasType = mpl::aux::has_type<T>::value> struct nested_type { typedef typename T::type type; }; template<typename T> struct nested_type<T, false> { typedef T type; }; template<typename T, bool Applied> struct nested_type_if { typedef T type; static bool const applied = false; }; template<typename T> struct nested_type_if<T, true> : nested_type<T> { static bool const applied = true; }; template< typename R , typename Expr, typename State, typename Data BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity<R>::value) > struct make_ { typedef R type; static bool const applied = false; }; template< typename R , typename Expr, typename State, typename Data , bool IsApplyable = is_applyable<R>::value > struct make_if_ : make_<R, Expr, State, Data> {}; template<typename R, typename Expr, typename State, typename Data> struct make_if_<R, Expr, State, Data, true> : uncvref<typename when<_, R>::template impl<Expr, State, Data>::result_type> { static bool const applied = true; }; #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ == 0) // work around GCC bug template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data> struct make_if_<proto::expr<Tag, Args, N>, Expr, State, Data, false> { typedef proto::expr<Tag, Args, N> type; static bool const applied = false; }; // work around GCC bug template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data> struct make_if_<proto::basic_expr<Tag, Args, N>, Expr, State, Data, false> { typedef proto::basic_expr<Tag, Args, N> type; static bool const applied = false; }; #endif template<typename Type, bool IsAggregate = detail::is_aggregate_<Type>::value> struct construct_ { typedef Type result_type; BOOST_FORCEINLINE Type operator ()() const { return Type(); } // Other overloads generated by the preprocessor #include <boost/proto/transform/detail/construct_funop.hpp> }; template<typename Type> struct construct_<Type, true> { typedef Type result_type; BOOST_FORCEINLINE Type operator ()() const { return Type(); } // Other overloads generated by the preprocessor #include <boost/proto/transform/detail/construct_pod_funop.hpp> }; } /// \brief A PrimitiveTransform which prevents another PrimitiveTransform /// from being applied in an \c ObjectTransform. /// /// When building higher order transforms with <tt>make\<\></tt> or /// <tt>lazy\<\></tt>, 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 /// <tt>Bar<_>()</tt> with <tt>proto::terminal\<int\>::type</tt>: /// /// \code /// template<typename T> /// struct Bar /// {}; /// /// struct Foo /// : proto::when<_, Bar<_>() > /// {}; /// /// proto::terminal<int>::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 /// <tt>Bar\<_\></tt>, you would have to protect the \c _ to prevent /// it from being applied. You can use <tt>proto::protect\<\></tt> /// as follows: /// /// \code /// // OK: replace anything with Bar<_>() /// struct Foo /// : proto::when<_, Bar<protect<_> >() > /// {}; /// \endcode template<typename PrimitiveTransform> struct protect : transform<protect<PrimitiveTransform> > { template<typename, typename, typename> 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 <tt>make\<\></tt> 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 <tt>proto::is_callable\< type \>::value</tt> is \c true /// /// <tt>boost::result_of\<make\<T\<X0,X1,...\> \>(Expr, State, Data)\>::type</tt> /// is evaluated as follows. For each \c X in <tt>X0,X1,...</tt>, do: /// /// \li If \c X is a template like <tt>U\<Y0,Y1,...\></tt>, then let <tt>X'</tt> /// be <tt>boost::result_of\<make\<U\<Y0,Y1,...\> \>(Expr, State, Data)\>::type</tt> /// (which evaluates this procedure recursively). Note whether any /// substitutions took place during this operation. /// \li Otherwise, if \c X is a transform, then let <tt>X'</tt> be /// <tt>boost::result_of\<when\<_, X\>(Expr, State, Data)\>::type</tt>. /// Note that a substitution took place. /// \li Otherwise, let <tt>X'</tt> be \c X, and note that no substitution /// took place. /// \li If any substitutions took place in any of the above steps and /// <tt>T\<X0',X1',...\></tt> has a nested <tt>::type</tt> typedef, /// the result type is <tt>T\<X0',X1',...\>::type</tt>. /// \li Otherwise, the result type is <tt>T\<X0',X1',...\></tt>. /// /// Note that <tt>when\<\></tt> is implemented in terms of <tt>call\<\></tt> /// and <tt>make\<\></tt>, so the above procedure is evaluated recursively. template<typename Object> struct make : transform<make<Object> > { template<typename Expr, typename State, typename Data> struct impl : transform_impl<Expr, State, Data> { typedef typename detail::make_if_<Object, Expr, State, Data>::type result_type; /// \return <tt>result_type()</tt> BOOST_FORCEINLINE result_type operator ()( typename impl::expr_param , typename impl::state_param , typename impl::data_param ) const { return result_type(); } }; }; /// INTERNAL ONLY template<typename Fun> struct make<detail::msvc_fun_workaround<Fun> > : make<Fun> {}; // Other specializations generated by the preprocessor. #include <boost/proto/transform/detail/make.hpp> #include <boost/proto/transform/detail/make_gcc_workaround.hpp> /// INTERNAL ONLY /// template<typename Object> struct is_callable<make<Object> > : mpl::true_ {}; /// INTERNAL ONLY /// template<typename PrimitiveTransform> struct is_callable<protect<PrimitiveTransform> > : mpl::true_ {}; }} #if defined(_MSC_VER) # pragma warning(pop) #endif #endif