| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | /// \file make.hpp |
| 3 | /// Contains definition of the make<> transform. |
| 4 | // |
| 5 | // Copyright 2008 Eric Niebler. Distributed under the Boost |
| 6 | // Software License, Version 1.0. (See accompanying file |
| 7 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 8 | |
| 9 | #ifndef BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_2007 |
| 10 | #define BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_2007 |
| 11 | |
| 12 | #include <boost/detail/workaround.hpp> |
| 13 | #include <boost/preprocessor/repetition/enum.hpp> |
| 14 | #include <boost/preprocessor/repetition/enum_params.hpp> |
| 15 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
| 16 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> |
| 17 | #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> |
| 18 | #include <boost/preprocessor/repetition/repeat_from_to.hpp> |
| 19 | #include <boost/preprocessor/facilities/intercept.hpp> |
| 20 | #include <boost/preprocessor/cat.hpp> |
| 21 | #include <boost/preprocessor/iteration/iterate.hpp> |
| 22 | #include <boost/preprocessor/selection/max.hpp> |
| 23 | #include <boost/preprocessor/arithmetic/inc.hpp> |
| 24 | #include <boost/mpl/and.hpp> |
| 25 | #include <boost/mpl/aux_/has_type.hpp> |
| 26 | #include <boost/proto/detail/template_arity.hpp> |
| 27 | #include <boost/utility/result_of.hpp> |
| 28 | #include <boost/proto/proto_fwd.hpp> |
| 29 | #include <boost/proto/traits.hpp> |
| 30 | #include <boost/proto/args.hpp> |
| 31 | #include <boost/proto/transform/impl.hpp> |
| 32 | #include <boost/proto/transform/detail/pack.hpp> |
| 33 | #include <boost/proto/detail/as_lvalue.hpp> |
| 34 | #include <boost/proto/detail/ignore_unused.hpp> |
| 35 | |
| 36 | #if defined(_MSC_VER) |
| 37 | # pragma warning(push) |
| 38 | # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined |
| 39 | #endif |
| 40 | |
| 41 | namespace boost { namespace proto |
| 42 | { |
| 43 | namespace detail |
| 44 | { |
| 45 | template<typename T> |
| 46 | struct is_applyable |
| 47 | : mpl::and_<is_callable<T>, is_transform<T> > |
| 48 | {}; |
| 49 | |
| 50 | template<typename T, bool HasType = mpl::aux::has_type<T>::value> |
| 51 | struct nested_type |
| 52 | { |
| 53 | typedef typename T::type type; |
| 54 | }; |
| 55 | |
| 56 | template<typename T> |
| 57 | struct nested_type<T, false> |
| 58 | { |
| 59 | typedef T type; |
| 60 | }; |
| 61 | |
| 62 | template<typename T, bool Applied> |
| 63 | struct nested_type_if |
| 64 | { |
| 65 | typedef T type; |
| 66 | static bool const applied = false; |
| 67 | }; |
| 68 | |
| 69 | template<typename T> |
| 70 | struct nested_type_if<T, true> |
| 71 | : nested_type<T> |
| 72 | { |
| 73 | static bool const applied = true; |
| 74 | }; |
| 75 | |
| 76 | template< |
| 77 | typename R |
| 78 | , typename Expr, typename State, typename Data |
| 79 | BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity<R>::value) |
| 80 | > |
| 81 | struct make_ |
| 82 | { |
| 83 | typedef R type; |
| 84 | static bool const applied = false; |
| 85 | }; |
| 86 | |
| 87 | template< |
| 88 | typename R |
| 89 | , typename Expr, typename State, typename Data |
| 90 | , bool IsApplyable = is_applyable<R>::value |
| 91 | > |
| 92 | struct make_if_ |
| 93 | : make_<R, Expr, State, Data> |
| 94 | {}; |
| 95 | |
| 96 | template<typename R, typename Expr, typename State, typename Data> |
| 97 | struct make_if_<R, Expr, State, Data, true> |
| 98 | : uncvref<typename when<_, R>::template impl<Expr, State, Data>::result_type> |
| 99 | { |
| 100 | static bool const applied = true; |
| 101 | }; |
| 102 | |
| 103 | #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ == 0) |
| 104 | // work around GCC bug |
| 105 | template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data> |
| 106 | struct make_if_<proto::expr<Tag, Args, N>, Expr, State, Data, false> |
| 107 | { |
| 108 | typedef proto::expr<Tag, Args, N> type; |
| 109 | static bool const applied = false; |
| 110 | }; |
| 111 | |
| 112 | // work around GCC bug |
| 113 | template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data> |
| 114 | struct make_if_<proto::basic_expr<Tag, Args, N>, Expr, State, Data, false> |
| 115 | { |
| 116 | typedef proto::basic_expr<Tag, Args, N> type; |
| 117 | static bool const applied = false; |
| 118 | }; |
| 119 | #endif |
| 120 | |
| 121 | template<typename Type, bool IsAggregate = detail::is_aggregate_<Type>::value> |
| 122 | struct construct_ |
| 123 | { |
| 124 | typedef Type result_type; |
| 125 | |
| 126 | BOOST_FORCEINLINE |
| 127 | Type operator ()() const |
| 128 | { |
| 129 | return Type(); |
| 130 | } |
| 131 | |
| 132 | // Other overloads generated by the preprocessor |
| 133 | #include <boost/proto/transform/detail/construct_funop.hpp> |
| 134 | }; |
| 135 | |
| 136 | template<typename Type> |
| 137 | struct construct_<Type, true> |
| 138 | { |
| 139 | typedef Type result_type; |
| 140 | |
| 141 | BOOST_FORCEINLINE |
| 142 | Type operator ()() const |
| 143 | { |
| 144 | return Type(); |
| 145 | } |
| 146 | |
| 147 | // Other overloads generated by the preprocessor |
| 148 | #include <boost/proto/transform/detail/construct_pod_funop.hpp> |
| 149 | }; |
| 150 | |
| 151 | } |
| 152 | |
| 153 | /// \brief A PrimitiveTransform which prevents another PrimitiveTransform |
| 154 | /// from being applied in an \c ObjectTransform. |
| 155 | /// |
| 156 | /// When building higher order transforms with <tt>make\<\></tt> or |
| 157 | /// <tt>lazy\<\></tt>, you sometimes would like to build types that |
| 158 | /// are parameterized with Proto transforms. In such lambda-style |
| 159 | /// transforms, Proto will unhelpfully find all nested transforms |
| 160 | /// and apply them, even if you don't want them to be applied. Consider |
| 161 | /// the following transform, which will replace the \c _ in |
| 162 | /// <tt>Bar<_>()</tt> with <tt>proto::terminal\<int\>::type</tt>: |
| 163 | /// |
| 164 | /// \code |
| 165 | /// template<typename T> |
| 166 | /// struct Bar |
| 167 | /// {}; |
| 168 | /// |
| 169 | /// struct Foo |
| 170 | /// : proto::when<_, Bar<_>() > |
| 171 | /// {}; |
| 172 | /// |
| 173 | /// proto::terminal<int>::type i = {0}; |
| 174 | /// |
| 175 | /// int main() |
| 176 | /// { |
| 177 | /// Foo()(i); |
| 178 | /// std::cout << typeid(Foo()(i)).name() << std::endl; |
| 179 | /// } |
| 180 | /// \endcode |
| 181 | /// |
| 182 | /// If you actually wanted to default-construct an object of type |
| 183 | /// <tt>Bar\<_\></tt>, you would have to protect the \c _ to prevent |
| 184 | /// it from being applied. You can use <tt>proto::protect\<\></tt> |
| 185 | /// as follows: |
| 186 | /// |
| 187 | /// \code |
| 188 | /// // OK: replace anything with Bar<_>() |
| 189 | /// struct Foo |
| 190 | /// : proto::when<_, Bar<protect<_> >() > |
| 191 | /// {}; |
| 192 | /// \endcode |
| 193 | template<typename PrimitiveTransform> |
| 194 | struct protect : transform<protect<PrimitiveTransform> > |
| 195 | { |
| 196 | template<typename, typename, typename> |
| 197 | struct impl |
| 198 | { |
| 199 | typedef PrimitiveTransform result_type; |
| 200 | }; |
| 201 | }; |
| 202 | |
| 203 | /// \brief A PrimitiveTransform which computes a type by evaluating any |
| 204 | /// nested transforms and then constructs an object of that type. |
| 205 | /// |
| 206 | /// The <tt>make\<\></tt> transform checks to see if \c Object is a template. |
| 207 | /// If it is, the template type is disassembled to find nested transforms. |
| 208 | /// Proto considers the following types to represent transforms: |
| 209 | /// |
| 210 | /// \li Function types |
| 211 | /// \li Function pointer types |
| 212 | /// \li Types for which <tt>proto::is_callable\< type \>::value</tt> is \c true |
| 213 | /// |
| 214 | /// <tt>boost::result_of\<make\<T\<X0,X1,...\> \>(Expr, State, Data)\>::type</tt> |
| 215 | /// is evaluated as follows. For each \c X in <tt>X0,X1,...</tt>, do: |
| 216 | /// |
| 217 | /// \li If \c X is a template like <tt>U\<Y0,Y1,...\></tt>, then let <tt>X'</tt> |
| 218 | /// be <tt>boost::result_of\<make\<U\<Y0,Y1,...\> \>(Expr, State, Data)\>::type</tt> |
| 219 | /// (which evaluates this procedure recursively). Note whether any |
| 220 | /// substitutions took place during this operation. |
| 221 | /// \li Otherwise, if \c X is a transform, then let <tt>X'</tt> be |
| 222 | /// <tt>boost::result_of\<when\<_, X\>(Expr, State, Data)\>::type</tt>. |
| 223 | /// Note that a substitution took place. |
| 224 | /// \li Otherwise, let <tt>X'</tt> be \c X, and note that no substitution |
| 225 | /// took place. |
| 226 | /// \li If any substitutions took place in any of the above steps and |
| 227 | /// <tt>T\<X0',X1',...\></tt> has a nested <tt>::type</tt> typedef, |
| 228 | /// the result type is <tt>T\<X0',X1',...\>::type</tt>. |
| 229 | /// \li Otherwise, the result type is <tt>T\<X0',X1',...\></tt>. |
| 230 | /// |
| 231 | /// Note that <tt>when\<\></tt> is implemented in terms of <tt>call\<\></tt> |
| 232 | /// and <tt>make\<\></tt>, so the above procedure is evaluated recursively. |
| 233 | template<typename Object> |
| 234 | struct make : transform<make<Object> > |
| 235 | { |
| 236 | template<typename Expr, typename State, typename Data> |
| 237 | struct impl : transform_impl<Expr, State, Data> |
| 238 | { |
| 239 | typedef typename detail::make_if_<Object, Expr, State, Data>::type result_type; |
| 240 | |
| 241 | /// \return <tt>result_type()</tt> |
| 242 | BOOST_FORCEINLINE |
| 243 | result_type operator ()( |
| 244 | typename impl::expr_param |
| 245 | , typename impl::state_param |
| 246 | , typename impl::data_param |
| 247 | ) const |
| 248 | { |
| 249 | return result_type(); |
| 250 | } |
| 251 | }; |
| 252 | }; |
| 253 | |
| 254 | /// INTERNAL ONLY |
| 255 | template<typename Fun> |
| 256 | struct make<detail::msvc_fun_workaround<Fun> > |
| 257 | : make<Fun> |
| 258 | {}; |
| 259 | |
| 260 | // Other specializations generated by the preprocessor. |
| 261 | #include <boost/proto/transform/detail/make.hpp> |
| 262 | #include <boost/proto/transform/detail/make_gcc_workaround.hpp> |
| 263 | |
| 264 | /// INTERNAL ONLY |
| 265 | /// |
| 266 | template<typename Object> |
| 267 | struct is_callable<make<Object> > |
| 268 | : mpl::true_ |
| 269 | {}; |
| 270 | |
| 271 | /// INTERNAL ONLY |
| 272 | /// |
| 273 | template<typename PrimitiveTransform> |
| 274 | struct is_callable<protect<PrimitiveTransform> > |
| 275 | : mpl::true_ |
| 276 | {}; |
| 277 | |
| 278 | }} |
| 279 | |
| 280 | #if defined(_MSC_VER) |
| 281 | # pragma warning(pop) |
| 282 | #endif |
| 283 | |
| 284 | #endif |
| 285 | |