make_expr.hpp 19 KB

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