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 operator ()boost::proto::call::impl2125 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 operator ()boost::proto::call::impl2175 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 operator ()boost::proto::call::impl2195 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 operator ()boost::proto::call::impl2249 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 operator ()boost::proto::call::impl2271 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 operator ()boost::proto::call::impl2333 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 operator ()boost::proto::call::impl2357 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