| 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 |
| 292 | 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 |
| 358 | 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 |
| 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 |
| 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 |
| 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 |
| 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 | |