call.hpp 16 KB

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