Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file make.hpp Chris@16: /// Contains definition of the make<> 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_MAKE_HPP_EAN_12_02_2007 Chris@16: #define BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_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 Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include 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: namespace boost { namespace proto Chris@16: { Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct is_applyable Chris@16: : mpl::and_, is_transform > Chris@16: {}; Chris@16: Chris@16: template::value> Chris@16: struct nested_type Chris@16: { Chris@16: typedef typename T::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct nested_type Chris@16: { Chris@16: typedef T type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct nested_type_if Chris@16: { Chris@16: typedef T type; Chris@16: static bool const applied = false; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct nested_type_if Chris@16: : nested_type Chris@16: { Chris@16: static bool const applied = true; Chris@16: }; Chris@16: Chris@16: template< Chris@16: typename R Chris@16: , typename Expr, typename State, typename Data Chris@16: BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity::value) Chris@16: > Chris@16: struct make_ Chris@16: { Chris@16: typedef R type; Chris@16: static bool const applied = false; Chris@16: }; Chris@16: Chris@16: template< Chris@16: typename R Chris@16: , typename Expr, typename State, typename Data Chris@16: , bool IsApplyable = is_applyable::value Chris@16: > Chris@16: struct make_if_ Chris@16: : make_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct make_if_ Chris@16: : uncvref::template impl::result_type> Chris@16: { Chris@16: static bool const applied = true; Chris@16: }; Chris@16: Chris@16: #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ == 0) Chris@16: // work around GCC bug Chris@16: template Chris@16: struct make_if_, Expr, State, Data, false> Chris@16: { Chris@16: typedef proto::expr type; Chris@16: static bool const applied = false; Chris@16: }; Chris@16: Chris@16: // work around GCC bug Chris@16: template Chris@16: struct make_if_, Expr, State, Data, false> Chris@16: { Chris@16: typedef proto::basic_expr type; Chris@16: static bool const applied = false; Chris@16: }; Chris@16: #endif Chris@16: Chris@16: template::value> Chris@16: struct construct_ Chris@16: { Chris@16: typedef Type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: Type operator ()() const Chris@16: { Chris@16: return Type(); Chris@16: } Chris@16: Chris@16: // Other overloads generated by the preprocessor Chris@16: #include Chris@16: }; Chris@16: Chris@16: template Chris@16: struct construct_ Chris@16: { Chris@16: typedef Type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: Type operator ()() const Chris@16: { Chris@16: return Type(); Chris@16: } Chris@16: Chris@16: // Other overloads generated by the preprocessor Chris@16: #include Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: /// \brief A PrimitiveTransform which prevents another PrimitiveTransform Chris@16: /// from being applied in an \c ObjectTransform. Chris@16: /// Chris@16: /// When building higher order transforms with make\<\> or Chris@16: /// lazy\<\>, you sometimes would like to build types that Chris@16: /// are parameterized with Proto transforms. In such lambda-style Chris@16: /// transforms, Proto will unhelpfully find all nested transforms Chris@16: /// and apply them, even if you don't want them to be applied. Consider Chris@16: /// the following transform, which will replace the \c _ in Chris@16: /// Bar<_>() with proto::terminal\::type: Chris@16: /// Chris@16: /// \code Chris@16: /// template Chris@16: /// struct Bar Chris@16: /// {}; Chris@16: /// Chris@16: /// struct Foo Chris@16: /// : proto::when<_, Bar<_>() > Chris@16: /// {}; Chris@16: /// Chris@16: /// proto::terminal::type i = {0}; Chris@16: /// Chris@16: /// int main() Chris@16: /// { Chris@16: /// Foo()(i); Chris@16: /// std::cout << typeid(Foo()(i)).name() << std::endl; Chris@16: /// } Chris@16: /// \endcode Chris@16: /// Chris@16: /// If you actually wanted to default-construct an object of type Chris@16: /// Bar\<_\>, you would have to protect the \c _ to prevent Chris@16: /// it from being applied. You can use proto::protect\<\> Chris@16: /// as follows: Chris@16: /// Chris@16: /// \code Chris@16: /// // OK: replace anything with Bar<_>() Chris@16: /// struct Foo Chris@16: /// : proto::when<_, Bar >() > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: template Chris@16: struct protect : transform > Chris@16: { Chris@16: template Chris@16: struct impl Chris@16: { Chris@16: typedef PrimitiveTransform result_type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: /// \brief A PrimitiveTransform which computes a type by evaluating any Chris@16: /// nested transforms and then constructs an object of that type. Chris@16: /// Chris@16: /// The make\<\> transform checks to see if \c Object is a template. Chris@16: /// If it is, the template type is disassembled to find nested transforms. Chris@16: /// Proto considers the following types to represent transforms: Chris@16: /// Chris@16: /// \li Function types Chris@16: /// \li Function pointer types Chris@16: /// \li Types for which proto::is_callable\< type \>::value is \c true Chris@16: /// Chris@16: /// boost::result_of\ \>(Expr, State, Data)\>::type Chris@16: /// is evaluated as follows. For each \c X in X0,X1,..., do: Chris@16: /// Chris@16: /// \li If \c X is a template like U\, then let X' Chris@16: /// be boost::result_of\ \>(Expr, State, Data)\>::type Chris@16: /// (which evaluates this procedure recursively). Note whether any Chris@16: /// substitutions took place during this operation. Chris@16: /// \li Otherwise, if \c X is a transform, then let X' be Chris@16: /// boost::result_of\(Expr, State, Data)\>::type. Chris@16: /// Note that a substitution took place. Chris@16: /// \li Otherwise, let X' be \c X, and note that no substitution Chris@16: /// took place. Chris@16: /// \li If any substitutions took place in any of the above steps and Chris@16: /// T\ has a nested ::type typedef, Chris@16: /// the result type is T\::type. Chris@16: /// \li Otherwise, the result type is T\. Chris@16: /// Chris@16: /// Note that when\<\> is implemented in terms of call\<\> Chris@16: /// and make\<\>, so the above procedure is evaluated recursively. Chris@16: template Chris@16: struct make : transform > Chris@16: { Chris@16: template Chris@16: struct impl : transform_impl Chris@16: { Chris@16: typedef typename detail::make_if_::type result_type; Chris@16: Chris@16: /// \return result_type() Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl::expr_param Chris@16: , typename impl::state_param Chris@16: , typename impl::data_param Chris@16: ) const Chris@16: { Chris@16: return result_type(); Chris@16: } Chris@16: }; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: struct make > Chris@16: : make Chris@16: {}; Chris@16: Chris@16: // Other specializations generated by the preprocessor. Chris@16: #include 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: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_callable > Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: }} Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif