| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | /// \file call.hpp |
| 3 | /// Contains definition of the call<> 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_CALL_HPP_EAN_11_02_2007 |
| 10 | #define BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007 |
| 11 | |
| 12 | #if defined(_MSC_VER) |
| 13 | # pragma warning(push) |
| 14 | # pragma warning(disable: 4714) // function 'xxx' marked as __forceinline not inlined |
| 15 | #endif |
| 16 | |
| 17 | #include <boost/preprocessor/cat.hpp> |
| 18 | #include <boost/preprocessor/facilities/intercept.hpp> |
| 19 | #include <boost/preprocessor/iteration/iterate.hpp> |
| 20 | #include <boost/preprocessor/repetition/enum.hpp> |
| 21 | #include <boost/preprocessor/repetition/repeat.hpp> |
| 22 | #include <boost/preprocessor/repetition/enum_params.hpp> |
| 23 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> |
| 24 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
| 25 | #include <boost/ref.hpp> |
| 26 | #include <boost/utility/result_of.hpp> |
| 27 | #include <boost/proto/proto_fwd.hpp> |
| 28 | #include <boost/proto/traits.hpp> |
| 29 | #include <boost/proto/transform/impl.hpp> |
| 30 | #include <boost/proto/detail/as_lvalue.hpp> |
| 31 | #include <boost/proto/detail/poly_function.hpp> |
| 32 | #include <boost/proto/transform/detail/pack.hpp> |
| 33 | |
| 34 | namespace boost { namespace proto |
| 35 | { |
| 36 | /// \brief Wrap \c PrimitiveTransform so that <tt>when\<\></tt> knows |
| 37 | /// it is callable. Requires that the parameter is actually a |
| 38 | /// PrimitiveTransform. |
| 39 | /// |
| 40 | /// This form of <tt>call\<\></tt> is useful for annotating an |
| 41 | /// arbitrary PrimitiveTransform as callable when using it with |
| 42 | /// <tt>when\<\></tt>. Consider the following transform, which |
| 43 | /// is parameterized with another transform. |
| 44 | /// |
| 45 | /// \code |
| 46 | /// template<typename Grammar> |
| 47 | /// struct Foo |
| 48 | /// : when< |
| 49 | /// unary_plus<Grammar> |
| 50 | /// , Grammar(_child) // May or may not work. |
| 51 | /// > |
| 52 | /// {}; |
| 53 | /// \endcode |
| 54 | /// |
| 55 | /// The problem with the above is that <tt>when\<\></tt> may or |
| 56 | /// may not recognize \c Grammar as callable, depending on how |
| 57 | /// \c Grammar is implemented. (See <tt>is_callable\<\></tt> for |
| 58 | /// a discussion of this issue.) You can guard against |
| 59 | /// the issue by wrapping \c Grammar in <tt>call\<\></tt>, such |
| 60 | /// as: |
| 61 | /// |
| 62 | /// \code |
| 63 | /// template<typename Grammar> |
| 64 | /// struct Foo |
| 65 | /// : when< |
| 66 | /// unary_plus<Grammar> |
| 67 | /// , call<Grammar>(_child) // OK, this works |
| 68 | /// > |
| 69 | /// {}; |
| 70 | /// \endcode |
| 71 | /// |
| 72 | /// The above could also have been written as: |
| 73 | /// |
| 74 | /// \code |
| 75 | /// template<typename Grammar> |
| 76 | /// struct Foo |
| 77 | /// : when< |
| 78 | /// unary_plus<Grammar> |
| 79 | /// , call<Grammar(_child)> // OK, this works, too |
| 80 | /// > |
| 81 | /// {}; |
| 82 | /// \endcode |
| 83 | template<typename PrimitiveTransform> |
| 84 | struct call |
| 85 | : PrimitiveTransform |
| 86 | {}; |
| 87 | |
| 88 | /// \brief A specialization that treats function pointer Transforms as |
| 89 | /// if they were function type Transforms. |
| 90 | /// |
| 91 | /// This specialization requires that \c Fun is actually a function type. |
| 92 | /// |
| 93 | /// This specialization is required for nested transforms such as |
| 94 | /// <tt>call\<T0(T1(_))\></tt>. In C++, functions that are used as |
| 95 | /// parameters to other functions automatically decay to funtion |
| 96 | /// pointer types. In other words, the type <tt>T0(T1(_))</tt> is |
| 97 | /// indistinguishable from <tt>T0(T1(*)(_))</tt>. This specialization |
| 98 | /// is required to handle these nested function pointer type transforms |
| 99 | /// properly. |
| 100 | template<typename Fun> |
| 101 | struct call<Fun *> |
| 102 | : call<Fun> |
| 103 | {}; |
| 104 | |
| 105 | /// INTERNAL ONLY |
| 106 | template<typename Fun> |
| 107 | struct call<detail::msvc_fun_workaround<Fun> > |
| 108 | : call<Fun> |
| 109 | {}; |
| 110 | |
| 111 | /// \brief Either call the PolymorphicFunctionObject with 0 |
| 112 | /// arguments, or invoke the PrimitiveTransform with 3 |
| 113 | /// arguments. |
| 114 | template<typename Fun> |
| 115 | struct call<Fun()> : transform<call<Fun()> > |
| 116 | { |
| 117 | /// INTERNAL ONLY |
| 118 | template<typename Expr, typename State, typename Data, bool B> |
| 119 | struct impl2 |
| 120 | : transform_impl<Expr, State, Data> |
| 121 | { |
| 122 | typedef typename BOOST_PROTO_RESULT_OF<Fun()>::type result_type; |
| 123 | |
| 124 | BOOST_FORCEINLINE |
| 125 | result_type operator()( |
| 126 | typename impl2::expr_param |
| 127 | , typename impl2::state_param |
| 128 | , typename impl2::data_param |
| 129 | ) const |
| 130 | { |
| 131 | return Fun()(); |
| 132 | } |
| 133 | }; |
| 134 | |
| 135 | /// INTERNAL ONLY |
| 136 | template<typename Expr, typename State, typename Data> |
| 137 | struct impl2<Expr, State, Data, true> |
| 138 | : Fun::template impl<Expr, State, Data> |
| 139 | {}; |
| 140 | |
| 141 | /// Either call the PolymorphicFunctionObject \c Fun with 0 arguments; or |
| 142 | /// invoke the PrimitiveTransform \c Fun with 3 arguments: the current |
| 143 | /// expression, state, and data. |
| 144 | /// |
| 145 | /// If \c Fun is a nullary PolymorphicFunctionObject, return <tt>Fun()()</tt>. |
| 146 | /// Otherwise, return <tt>Fun()(e, s, d)</tt>. |
| 147 | /// |
| 148 | /// \param e The current expression |
| 149 | /// \param s The current state |
| 150 | /// \param d An arbitrary data |
| 151 | |
| 152 | /// If \c Fun is a nullary PolymorphicFunctionObject, \c type is a typedef |
| 153 | /// for <tt>boost::result_of\<Fun()\>::type</tt>. Otherwise, it is |
| 154 | /// a typedef for <tt>boost::result_of\<Fun(Expr, State, Data)\>::type</tt>. |
| 155 | template<typename Expr, typename State, typename Data> |
| 156 | struct impl |
| 157 | : impl2<Expr, State, Data, detail::is_transform_<Fun>::value> |
| 158 | {}; |
| 159 | }; |
| 160 | |
| 161 | /// \brief Either call the PolymorphicFunctionObject with 1 |
| 162 | /// argument, or invoke the PrimitiveTransform with 3 |
| 163 | /// arguments. |
| 164 | template<typename Fun, typename A0> |
| 165 | struct call<Fun(A0)> : transform<call<Fun(A0)> > |
| 166 | { |
| 167 | template<typename Expr, typename State, typename Data, bool B> |
| 168 | struct impl2 |
| 169 | : transform_impl<Expr, State, Data> |
| 170 | { |
| 171 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 172 | typedef typename detail::poly_function_traits<Fun, Fun(a0)>::result_type result_type; |
| 173 | |
| 174 | BOOST_FORCEINLINE |
| 175 | result_type operator ()( |
| 176 | typename impl2::expr_param e |
| 177 | , typename impl2::state_param s |
| 178 | , typename impl2::data_param d |
| 179 | ) const |
| 180 | { |
| 181 | return typename detail::poly_function_traits<Fun, Fun(a0)>::function_type()( |
| 182 | detail::as_lvalue(typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d)) |
| 183 | ); |
| 184 | } |
| 185 | }; |
| 186 | |
| 187 | template<typename Expr, typename State, typename Data> |
| 188 | struct impl2<Expr, State, Data, true> |
| 189 | : transform_impl<Expr, State, Data> |
| 190 | { |
| 191 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 192 | typedef typename Fun::template impl<a0, State, Data>::result_type result_type; |
| 193 | |
| 194 | BOOST_FORCEINLINE |
| 195 | result_type operator ()( |
| 196 | typename impl2::expr_param e |
| 197 | , typename impl2::state_param s |
| 198 | , typename impl2::data_param d |
| 199 | ) const |
| 200 | { |
| 201 | return typename Fun::template impl<a0, State, Data>()( |
| 202 | typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d) |
| 203 | , s |
| 204 | , d |
| 205 | ); |
| 206 | } |
| 207 | }; |
| 208 | /// Let \c x be <tt>when\<_, A0\>()(e, s, d)</tt> and \c X |
| 209 | /// be the type of \c x. |
| 210 | /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, |
| 211 | /// then \c type is a typedef for <tt>boost::result_of\<Fun(X)\>::type</tt>. |
| 212 | /// Otherwise, it is a typedef for <tt>boost::result_of\<Fun(X, State, Data)\>::type</tt>. |
| 213 | |
| 214 | /// Either call the PolymorphicFunctionObject with 1 argument: |
| 215 | /// the result of applying the \c A0 transform; or |
| 216 | /// invoke the PrimitiveTransform with 3 arguments: |
| 217 | /// result of applying the \c A0 transform, the state, and the |
| 218 | /// data. |
| 219 | /// |
| 220 | /// Let \c x be <tt>when\<_, A0\>()(e, s, d)</tt>. |
| 221 | /// If \c Fun is a unary PolymorphicFunctionObject that accepts \c x, |
| 222 | /// then return <tt>Fun()(x)</tt>. Otherwise, return |
| 223 | /// <tt>Fun()(x, s, d)</tt>. |
| 224 | /// |
| 225 | /// \param e The current expression |
| 226 | /// \param s The current state |
| 227 | /// \param d An arbitrary data |
| 228 | template<typename Expr, typename State, typename Data> |
| 229 | struct impl |
| 230 | : impl2<Expr, State, Data, detail::is_transform_<Fun>::value> |
| 231 | {}; |
| 232 | }; |
| 233 | |
| 234 | /// \brief Either call the PolymorphicFunctionObject with 2 |
| 235 | /// arguments, or invoke the PrimitiveTransform with 3 |
| 236 | /// arguments. |
| 237 | template<typename Fun, typename A0, typename A1> |
| 238 | struct call<Fun(A0, A1)> : transform<call<Fun(A0, A1)> > |
| 239 | { |
| 240 | template<typename Expr, typename State, typename Data, bool B> |
| 241 | struct impl2 |
| 242 | : transform_impl<Expr, State, Data> |
| 243 | { |
| 244 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 245 | typedef typename when<_, A1>::template impl<Expr, State, Data>::result_type a1; |
| 246 | typedef typename detail::poly_function_traits<Fun, Fun(a0, a1)>::result_type result_type; |
| 247 | |
| 248 | BOOST_FORCEINLINE |
| 249 | result_type operator ()( |
| 250 | typename impl2::expr_param e |
| 251 | , typename impl2::state_param s |
| 252 | , typename impl2::data_param d |
| 253 | ) const |
| 254 | { |
| 255 | return typename detail::poly_function_traits<Fun, Fun(a0, a1)>::function_type()( |
| 256 | detail::as_lvalue(typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d)) |
| 257 | , detail::as_lvalue(typename when<_, A1>::template impl<Expr, State, Data>()(e, s, d)) |
| 258 | ); |
| 259 | } |
| 260 | }; |
| 261 | |
| 262 | template<typename Expr, typename State, typename Data> |
| 263 | struct impl2<Expr, State, Data, true> |
| 264 | : transform_impl<Expr, State, Data> |
| 265 | { |
| 266 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 267 | typedef typename when<_, A1>::template impl<Expr, State, Data>::result_type a1; |
| 268 | typedef typename Fun::template impl<a0, a1, Data>::result_type result_type; |
| 269 | |
| 270 | BOOST_FORCEINLINE |
| 271 | result_type operator ()( |
| 272 | typename impl2::expr_param e |
| 273 | , typename impl2::state_param s |
| 274 | , typename impl2::data_param d |
| 275 | ) const |
| 276 | { |
| 277 | return typename Fun::template impl<a0, a1, Data>()( |
| 278 | typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d) |
| 279 | , typename when<_, A1>::template impl<Expr, State, Data>()(e, s, d) |
| 280 | , d |
| 281 | ); |
| 282 | } |
| 283 | }; |
| 284 | |
| 285 | /// Let \c x be <tt>when\<_, A0\>()(e, s, d)</tt> and \c X |
| 286 | /// be the type of \c x. |
| 287 | /// Let \c y be <tt>when\<_, A1\>()(e, s, d)</tt> and \c Y |
| 288 | /// be the type of \c y. |
| 289 | /// If \c Fun is a binary PolymorphicFunction object that accepts \c x |
| 290 | /// and \c y, then \c type is a typedef for |
| 291 | /// <tt>boost::result_of\<Fun(X, Y)\>::type</tt>. Otherwise, it is |
| 292 | /// a typedef for <tt>boost::result_of\<Fun(X, Y, Data)\>::type</tt>. |
| 293 | |
| 294 | /// Either call the PolymorphicFunctionObject with 2 arguments: |
| 295 | /// the result of applying the \c A0 transform, and the |
| 296 | /// result of applying the \c A1 transform; or invoke the |
| 297 | /// PrimitiveTransform with 3 arguments: the result of applying |
| 298 | /// the \c A0 transform, the result of applying the \c A1 |
| 299 | /// transform, and the data. |
| 300 | /// |
| 301 | /// Let \c x be <tt>when\<_, A0\>()(e, s, d)</tt>. |
| 302 | /// Let \c y be <tt>when\<_, A1\>()(e, s, d)</tt>. |
| 303 | /// If \c Fun is a binary PolymorphicFunction object that accepts \c x |
| 304 | /// and \c y, return <tt>Fun()(x, y)</tt>. Otherwise, return |
| 305 | /// <tt>Fun()(x, y, d)</tt>. |
| 306 | /// |
| 307 | /// \param e The current expression |
| 308 | /// \param s The current state |
| 309 | /// \param d An arbitrary data |
| 310 | template<typename Expr, typename State, typename Data> |
| 311 | struct impl |
| 312 | : impl2<Expr, State, Data, detail::is_transform_<Fun>::value> |
| 313 | {}; |
| 314 | }; |
| 315 | |
| 316 | /// \brief Call the PolymorphicFunctionObject or the |
| 317 | /// PrimitiveTransform with the current expression, state |
| 318 | /// and data, transformed according to \c A0, \c A1, and |
| 319 | /// \c A2, respectively. |
| 320 | template<typename Fun, typename A0, typename A1, typename A2> |
| 321 | struct call<Fun(A0, A1, A2)> : transform<call<Fun(A0, A1, A2)> > |
| 322 | { |
| 323 | template<typename Expr, typename State, typename Data, bool B> |
| 324 | struct impl2 |
| 325 | : transform_impl<Expr, State, Data> |
| 326 | { |
| 327 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 328 | typedef typename when<_, A1>::template impl<Expr, State, Data>::result_type a1; |
| 329 | typedef typename when<_, A2>::template impl<Expr, State, Data>::result_type a2; |
| 330 | typedef typename detail::poly_function_traits<Fun, Fun(a0, a1, a2)>::result_type result_type; |
| 331 | |
| 332 | BOOST_FORCEINLINE |
| 333 | result_type operator ()( |
| 334 | typename impl2::expr_param e |
| 335 | , typename impl2::state_param s |
| 336 | , typename impl2::data_param d |
| 337 | ) const |
| 338 | { |
| 339 | return typename detail::poly_function_traits<Fun, Fun(a0, a1, a2)>::function_type()( |
| 340 | detail::as_lvalue(typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d)) |
| 341 | , detail::as_lvalue(typename when<_, A1>::template impl<Expr, State, Data>()(e, s, d)) |
| 342 | , detail::as_lvalue(typename when<_, A2>::template impl<Expr, State, Data>()(e, s, d)) |
| 343 | ); |
| 344 | } |
| 345 | }; |
| 346 | |
| 347 | template<typename Expr, typename State, typename Data> |
| 348 | struct impl2<Expr, State, Data, true> |
| 349 | : transform_impl<Expr, State, Data> |
| 350 | { |
| 351 | typedef typename when<_, A0>::template impl<Expr, State, Data>::result_type a0; |
| 352 | typedef typename when<_, A1>::template impl<Expr, State, Data>::result_type a1; |
| 353 | typedef typename when<_, A2>::template impl<Expr, State, Data>::result_type a2; |
| 354 | typedef typename Fun::template impl<a0, a1, a2>::result_type result_type; |
| 355 | |
| 356 | BOOST_FORCEINLINE |
| 357 | result_type operator ()( |
| 358 | typename impl2::expr_param e |
| 359 | , typename impl2::state_param s |
| 360 | , typename impl2::data_param d |
| 361 | ) const |
| 362 | { |
| 363 | return typename Fun::template impl<a0, a1, a2>()( |
| 364 | typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d) |
| 365 | , typename when<_, A1>::template impl<Expr, State, Data>()(e, s, d) |
| 366 | , typename when<_, A2>::template impl<Expr, State, Data>()(e, s, d) |
| 367 | ); |
| 368 | } |
| 369 | }; |
| 370 | |
| 371 | /// Let \c x be <tt>when\<_, A0\>()(e, s, d)</tt>. |
| 372 | /// Let \c y be <tt>when\<_, A1\>()(e, s, d)</tt>. |
| 373 | /// Let \c z be <tt>when\<_, A2\>()(e, s, d)</tt>. |
| 374 | /// Return <tt>Fun()(x, y, z)</tt>. |
| 375 | /// |
| 376 | /// \param e The current expression |
| 377 | /// \param s The current state |
| 378 | /// \param d An arbitrary data |
| 379 | |
| 380 | template<typename Expr, typename State, typename Data> |
| 381 | struct impl |
| 382 | : impl2<Expr, State, Data, detail::is_transform_<Fun>::value> |
| 383 | {}; |
| 384 | }; |
| 385 | |
| 386 | #include <boost/proto/transform/detail/call.hpp> |
| 387 | |
| 388 | /// INTERNAL ONLY |
| 389 | /// |
| 390 | template<typename Fun> |
| 391 | struct is_callable<call<Fun> > |
| 392 | : mpl::true_ |
| 393 | {}; |
| 394 | |
| 395 | }} // namespace boost::proto |
| 396 | |
| 397 | #if defined(_MSC_VER) |
| 398 | # pragma warning(pop) |
| 399 | #endif |
| 400 | |
| 401 | #endif |
| 402 | |