1 /////////////////////////////////////////////////////////////////////////////// 2 /// \file make_expr.hpp 3 /// Definition of the \c make_expr() and \c unpack_expr() utilities for 4 /// building Proto expression nodes from child nodes or from a Fusion 5 /// sequence of child nodes, respectively. 6 // 7 // Copyright 2008 Eric Niebler. Distributed under the Boost 8 // Software License, Version 1.0. (See accompanying file 9 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 11 #ifndef BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 12 #define BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 13 14 #include <boost/preprocessor/cat.hpp> 15 #include <boost/preprocessor/arithmetic/inc.hpp> 16 #include <boost/preprocessor/arithmetic/dec.hpp> 17 #include <boost/preprocessor/arithmetic/sub.hpp> 18 #include <boost/preprocessor/punctuation/comma_if.hpp> 19 #include <boost/preprocessor/iteration/iterate.hpp> 20 #include <boost/preprocessor/facilities/intercept.hpp> 21 #include <boost/preprocessor/repetition/enum.hpp> 22 #include <boost/preprocessor/repetition/enum_params.hpp> 23 #include <boost/preprocessor/repetition/enum_binary_params.hpp> 24 #include <boost/preprocessor/repetition/enum_shifted_params.hpp> 25 #include <boost/preprocessor/repetition/enum_trailing_params.hpp> 26 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> 27 #include <boost/preprocessor/repetition/repeat.hpp> 28 #include <boost/ref.hpp> 29 #include <boost/mpl/if.hpp> 30 #include <boost/mpl/assert.hpp> 31 #include <boost/mpl/eval_if.hpp> 32 #include <boost/utility/enable_if.hpp> 33 #include <boost/type_traits/add_const.hpp> 34 #include <boost/type_traits/add_reference.hpp> 35 #include <boost/type_traits/remove_cv.hpp> 36 #include <boost/proto/proto_fwd.hpp> 37 #include <boost/proto/traits.hpp> 38 #include <boost/proto/domain.hpp> 39 #include <boost/proto/generate.hpp> 40 #include <boost/fusion/include/at_c.hpp> 41 #include <boost/fusion/include/begin.hpp> 42 #include <boost/fusion/include/next.hpp> 43 #include <boost/fusion/include/value_of.hpp> 44 #include <boost/fusion/include/size.hpp> 45 #include <boost/proto/detail/poly_function.hpp> 46 #include <boost/proto/detail/deprecated.hpp> 47 48 #if defined(_MSC_VER) 49 # pragma warning(push) 50 # pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored 51 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined 52 #endif 53 54 namespace boost { namespace proto 55 { 56 /// INTERNAL ONLY 57 /// 58 #define BOOST_PROTO_AS_CHILD_TYPE(Z, N, DATA) \ 59 typename boost::proto::detail::protoify< \ 60 BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, DATA), N) \ 61 , BOOST_PP_TUPLE_ELEM(3, 2, DATA) \ 62 >::result_type \ 63 /**/ 64 65 /// INTERNAL ONLY 66 /// 67 #define BOOST_PROTO_AS_CHILD(Z, N, DATA) \ 68 boost::proto::detail::protoify< \ 69 BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, DATA), N) \ 70 , BOOST_PP_TUPLE_ELEM(3, 2, DATA) \ 71 >()(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 1, DATA), N)) \ 72 /**/ 73 74 namespace detail 75 { 76 template<typename T, typename Domain> 77 struct protoify 78 : Domain::template as_expr<T> 79 {}; 80 81 template<typename T, typename Domain> 82 struct protoify<T &, Domain> 83 : Domain::template as_child<T> 84 {}; 85 86 template<typename T, typename Domain> 87 struct protoify<boost::reference_wrapper<T>, Domain> 88 : Domain::template as_child<T> 89 {}; 90 91 template<typename T, typename Domain> 92 struct protoify<boost::reference_wrapper<T> const, Domain> 93 : Domain::template as_child<T> 94 {}; 95 96 // Definition of detail::unpack_expr_ 97 #include <boost/proto/detail/unpack_expr_.hpp> 98 99 // Definition of detail::make_expr_ 100 #include <boost/proto/detail/make_expr_.hpp> 101 } 102 103 namespace result_of 104 { 105 /// \brief Metafunction that computes the return type of the 106 /// \c make_expr() function, with a domain deduced from the 107 /// domains of the children. 108 /// 109 /// Use the <tt>result_of::make_expr\<\></tt> metafunction to 110 /// compute the return type of the \c make_expr() function. 111 /// 112 /// In this specialization, the domain is deduced from the 113 /// domains of the child types. (If 114 /// <tt>is_domain\<A0\>::value</tt> is \c true, then another 115 /// specialization is selected.) 116 template< 117 typename Tag 118 , BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_ARITY, typename A) 119 , typename Void1 // = void 120 , typename Void2 // = void 121 > 122 struct make_expr 123 { 124 /// Same as <tt>result_of::make_expr\<Tag, D, A0, ... AN\>::type</tt> 125 /// where \c D is the deduced domain, which is calculated as follows: 126 /// 127 /// For each \c x in <tt>[0,N)</tt> (proceeding in order beginning with 128 /// <tt>x=0</tt>), if <tt>domain_of\<Ax\>::type</tt> is not 129 /// \c default_domain, then \c D is <tt>domain_of\<Ax\>::type</tt>. 130 /// Otherwise, \c D is \c default_domain. 131 typedef 132 typename detail::make_expr_< 133 Tag 134 , deduce_domain 135 BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) 136 >::result_type 137 type; 138 }; 139 140 /// \brief Metafunction that computes the return type of the 141 /// \c make_expr() function, within the specified domain. 142 /// 143 /// Use the <tt>result_of::make_expr\<\></tt> metafunction to compute 144 /// the return type of the \c make_expr() function. 145 template< 146 typename Tag 147 , typename Domain 148 BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, typename A) 149 > 150 struct make_expr< 151 Tag 152 , Domain 153 BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) 154 , typename Domain::proto_is_domain_ 155 > 156 { 157 /// If \c Tag is <tt>tag::terminal</tt>, then \c type is a 158 /// typedef for <tt>boost::result_of\<Domain(expr\<tag::terminal, 159 /// term\<A0\> \>)\>::type</tt>. 160 /// 161 /// Otherwise, \c type is a typedef for <tt>boost::result_of\<Domain(expr\<Tag, 162 /// listN\< as_child\<A0\>::type, ... as_child\<AN\>::type\>) 163 /// \>::type</tt>, where \c N is the number of non-void template 164 /// arguments, and <tt>as_child\<A\>::type</tt> is evaluated as 165 /// follows: 166 /// 167 /// \li If <tt>is_expr\<A\>::value</tt> is \c true, then the 168 /// child type is \c A. 169 /// \li If \c A is <tt>B &</tt> or <tt>cv boost::reference_wrapper\<B\></tt>, 170 /// and <tt>is_expr\<B\>::value</tt> is \c true, then the 171 /// child type is <tt>B &</tt>. 172 /// \li If <tt>is_expr\<A\>::value</tt> is \c false, then the 173 /// child type is <tt>boost::result_of\<Domain(expr\<tag::terminal, term\<A\> \> 174 /// )\>::type</tt>. 175 /// \li If \c A is <tt>B &</tt> or <tt>cv boost::reference_wrapper\<B\></tt>, 176 /// and <tt>is_expr\<B\>::value</tt> is \c false, then the 177 /// child type is <tt>boost::result_of\<Domain(expr\<tag::terminal, term\<B &\> \> 178 /// )\>::type</tt>. 179 typedef 180 typename detail::make_expr_< 181 Tag 182 , Domain 183 BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) 184 >::result_type 185 type; 186 }; 187 188 /// \brief Metafunction that computes the return type of the 189 /// \c unpack_expr() function, with a domain deduced from the 190 /// domains of the children. 191 /// 192 /// Use the <tt>result_of::unpack_expr\<\></tt> metafunction to 193 /// compute the return type of the \c unpack_expr() function. 194 /// 195 /// \c Sequence is a Fusion Forward Sequence. 196 /// 197 /// In this specialization, the domain is deduced from the 198 /// domains of the child types. (If 199 /// <tt>is_domain\<Sequence>::value</tt> is \c true, then another 200 /// specialization is selected.) 201 template< 202 typename Tag 203 , typename Sequence 204 , typename Void1 // = void 205 , typename Void2 // = void 206 > 207 struct unpack_expr 208 { 209 /// Let \c S be the type of a Fusion Random Access Sequence 210 /// equivalent to \c Sequence. Then \c type is the 211 /// same as <tt>result_of::make_expr\<Tag, 212 /// fusion::result_of::value_at_c\<S, 0\>::type, ... 213 /// fusion::result_of::value_at_c\<S, N-1\>::type\>::type</tt>, 214 /// where \c N is the size of \c S. 215 typedef 216 typename detail::unpack_expr_< 217 Tag 218 , deduce_domain 219 , Sequence 220 , fusion::result_of::size<Sequence>::type::value 221 >::type 222 type; 223 }; 224 225 /// \brief Metafunction that computes the return type of the 226 /// \c unpack_expr() function, within the specified domain. 227 /// 228 /// Use the <tt>result_of::make_expr\<\></tt> metafunction to compute 229 /// the return type of the \c make_expr() function. 230 template<typename Tag, typename Domain, typename Sequence> 231 struct unpack_expr<Tag, Domain, Sequence, typename Domain::proto_is_domain_> 232 { 233 /// Let \c S be the type of a Fusion Random Access Sequence 234 /// equivalent to \c Sequence. Then \c type is the 235 /// same as <tt>result_of::make_expr\<Tag, Domain, 236 /// fusion::result_of::value_at_c\<S, 0\>::type, ... 237 /// fusion::result_of::value_at_c\<S, N-1\>::type\>::type</tt>, 238 /// where \c N is the size of \c S. 239 typedef 240 typename detail::unpack_expr_< 241 Tag 242 , Domain 243 , Sequence 244 , fusion::result_of::size<Sequence>::type::value 245 >::type 246 type; 247 }; 248 } 249 250 namespace functional 251 { 252 /// \brief A callable function object equivalent to the 253 /// \c proto::make_expr() function. 254 /// 255 /// In all cases, <tt>functional::make_expr\<Tag, Domain\>()(a0, ... aN)</tt> 256 /// is equivalent to <tt>proto::make_expr\<Tag, Domain\>(a0, ... aN)</tt>. 257 /// 258 /// <tt>functional::make_expr\<Tag\>()(a0, ... aN)</tt> 259 /// is equivalent to <tt>proto::make_expr\<Tag\>(a0, ... aN)</tt>. 260 template<typename Tag, typename Domain /* = deduce_domain*/> 261 struct make_expr 262 { 263 BOOST_PROTO_CALLABLE() 264 BOOST_PROTO_POLY_FUNCTION() 265 266 template<typename Sig> 267 struct result; 268 269 template<typename This, typename A0> 270 struct result<This(A0)> 271 { 272 typedef 273 typename result_of::make_expr< 274 Tag 275 , Domain 276 , A0 277 >::type 278 type; 279 }; 280 281 /// Construct an expression node with tag type \c Tag 282 /// and in the domain \c Domain. 283 /// 284 /// \return <tt>proto::make_expr\<Tag, Domain\>(a0,...aN)</tt> 285 template<typename A0> 286 BOOST_FORCEINLINE 287 typename result_of::make_expr< 288 Tag 289 , Domain 290 , A0 const 291 >::type const operator ()boost::proto::functional::make_expr292 operator ()(A0 const &a0) const 293 { 294 return proto::detail::make_expr_< 295 Tag 296 , Domain 297 , A0 const 298 >()(a0); 299 } 300 301 // Additional overloads generated by the preprocessor ... 302 #include <boost/proto/detail/make_expr_funop.hpp> 303 304 /// INTERNAL ONLY 305 /// 306 template< 307 BOOST_PP_ENUM_BINARY_PARAMS( 308 BOOST_PROTO_MAX_ARITY 309 , typename A 310 , = void BOOST_PP_INTERCEPT 311 ) 312 > 313 struct impl 314 : detail::make_expr_< 315 Tag 316 , Domain 317 BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) 318 > 319 {}; 320 }; 321 322 /// \brief A callable function object equivalent to the 323 /// \c proto::unpack_expr() function. 324 /// 325 /// In all cases, <tt>functional::unpack_expr\<Tag, Domain\>()(seq)</tt> 326 /// is equivalent to <tt>proto::unpack_expr\<Tag, Domain\>(seq)</tt>. 327 /// 328 /// <tt>functional::unpack_expr\<Tag\>()(seq)</tt> 329 /// is equivalent to <tt>proto::unpack_expr\<Tag\>(seq)</tt>. 330 template<typename Tag, typename Domain /* = deduce_domain*/> 331 struct unpack_expr 332 { 333 BOOST_PROTO_CALLABLE() 334 335 template<typename Sig> 336 struct result; 337 338 template<typename This, typename Sequence> 339 struct result<This(Sequence)> 340 { 341 typedef 342 typename result_of::unpack_expr< 343 Tag 344 , Domain 345 , typename remove_reference<Sequence>::type 346 >::type 347 type; 348 }; 349 350 /// Construct an expression node with tag type \c Tag 351 /// and in the domain \c Domain. 352 /// 353 /// \param sequence A Fusion Forward Sequence 354 /// \return <tt>proto::unpack_expr\<Tag, Domain\>(sequence)</tt> 355 template<typename Sequence> 356 BOOST_FORCEINLINE 357 typename result_of::unpack_expr<Tag, Domain, Sequence const>::type const operator ()boost::proto::functional::unpack_expr358 operator ()(Sequence const &sequence) const 359 { 360 return proto::detail::unpack_expr_< 361 Tag 362 , Domain 363 , Sequence const 364 , fusion::result_of::size<Sequence>::type::value 365 >::call(sequence); 366 } 367 }; 368 369 } // namespace functional 370 371 /// \brief Construct an expression of the requested tag type 372 /// with a domain and with the specified arguments as children. 373 /// 374 /// This function template may be invoked either with or without 375 /// specifying a \c Domain argument. If no domain is specified, 376 /// the domain is deduced by examining in order the domains of 377 /// the given arguments and taking the first that is not 378 /// \c default_domain, if any such domain exists, or 379 /// \c default_domain otherwise. 380 /// 381 /// Let \c wrap_(x) be defined such that: 382 /// \li If \c x is a <tt>boost::reference_wrapper\<\></tt>, 383 /// \c wrap_(x) is equivalent to <tt>as_child\<Domain\>(x.get())</tt>. 384 /// \li Otherwise, \c wrap_(x) is equivalent to 385 /// <tt>as_expr\<Domain\>(x)</tt>. 386 /// 387 /// Let <tt>make_\<Tag\>(b0,...bN)</tt> be defined as 388 /// <tt>expr\<Tag, listN\<C0,...CN\> \>::make(c0,...cN)</tt> 389 /// where \c Bx is the type of \c bx. 390 /// 391 /// \return <tt>Domain()(make_\<Tag\>(wrap_(a0),...wrap_(aN)))</tt>. 392 template<typename Tag, typename A0> 393 BOOST_FORCEINLINE 394 typename lazy_disable_if< 395 is_domain<A0> 396 , result_of::make_expr< 397 Tag 398 , A0 const 399 > 400 >::type const make_expr(A0 const & a0)401 make_expr(A0 const &a0) 402 { 403 return proto::detail::make_expr_< 404 Tag 405 , deduce_domain 406 , A0 const 407 >()(a0); 408 } 409 410 /// \overload 411 /// 412 template<typename Tag, typename Domain, typename C0> 413 BOOST_FORCEINLINE 414 typename result_of::make_expr< 415 Tag 416 , Domain 417 , C0 const 418 >::type const make_expr(C0 const & c0)419 make_expr(C0 const &c0) 420 { 421 return proto::detail::make_expr_< 422 Tag 423 , Domain 424 , C0 const 425 >()(c0); 426 } 427 428 // Additional overloads generated by the preprocessor... 429 #include <boost/proto/detail/make_expr.hpp> 430 431 /// \brief Construct an expression of the requested tag type 432 /// with a domain and with childres from the specified Fusion 433 /// Forward Sequence. 434 /// 435 /// This function template may be invoked either with or without 436 /// specifying a \c Domain argument. If no domain is specified, 437 /// the domain is deduced by examining in order the domains of the 438 /// elements of \c sequence and taking the first that is not 439 /// \c default_domain, if any such domain exists, or 440 /// \c default_domain otherwise. 441 /// 442 /// Let \c s be a Fusion Random Access Sequence equivalent to \c sequence. 443 /// Let <tt>wrap_\<N\>(s)</tt>, where \c s has type \c S, be defined 444 /// such that: 445 /// \li If <tt>fusion::result_of::value_at_c\<S,N\>::type</tt> is a reference, 446 /// <tt>wrap_\<N\>(s)</tt> is equivalent to 447 /// <tt>as_child\<Domain\>(fusion::at_c\<N\>(s))</tt>. 448 /// \li Otherwise, <tt>wrap_\<N\>(s)</tt> is equivalent to 449 /// <tt>as_expr\<Domain\>(fusion::at_c\<N\>(s))</tt>. 450 /// 451 /// Let <tt>make_\<Tag\>(b0,...bN)</tt> be defined as 452 /// <tt>expr\<Tag, listN\<B0,...BN\> \>::make(b0,...bN)</tt> 453 /// where \c Bx is the type of \c bx. 454 /// 455 /// \param sequence a Fusion Forward Sequence. 456 /// \return <tt>Domain()(make_\<Tag\>(wrap_\<0\>(s),...wrap_\<N-1\>(s)))</tt>, 457 /// where N is the size of \c Sequence. 458 template<typename Tag, typename Sequence> 459 BOOST_FORCEINLINE 460 typename lazy_disable_if< 461 is_domain<Sequence> 462 , result_of::unpack_expr<Tag, Sequence const> 463 >::type const unpack_expr(Sequence const & sequence)464 unpack_expr(Sequence const &sequence) 465 { 466 return proto::detail::unpack_expr_< 467 Tag 468 , deduce_domain 469 , Sequence const 470 , fusion::result_of::size<Sequence>::type::value 471 >::call(sequence); 472 } 473 474 /// \overload 475 /// 476 template<typename Tag, typename Domain, typename Sequence2> 477 BOOST_FORCEINLINE 478 typename result_of::unpack_expr<Tag, Domain, Sequence2 const>::type const unpack_expr(Sequence2 const & sequence2)479 unpack_expr(Sequence2 const &sequence2) 480 { 481 return proto::detail::unpack_expr_< 482 Tag 483 , Domain 484 , Sequence2 const 485 , fusion::result_of::size<Sequence2>::type::value 486 >::call(sequence2); 487 } 488 489 /// INTERNAL ONLY 490 /// 491 template<typename Tag, typename Domain> 492 struct is_callable<functional::make_expr<Tag, Domain> > 493 : mpl::true_ 494 {}; 495 496 /// INTERNAL ONLY 497 /// 498 template<typename Tag, typename Domain> 499 struct is_callable<functional::unpack_expr<Tag, Domain> > 500 : mpl::true_ 501 {}; 502 503 }} 504 505 #if defined(_MSC_VER) 506 # pragma warning(pop) 507 #endif 508 509 #endif // BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 510