1 ///////////////////////////////////////////////////////////////////////////////
3 /// Contains definition of the call<> transform.
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)
9 #ifndef BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007
10 #define BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007
13 # pragma warning(push)
14 # pragma warning(disable: 4714) // function 'xxx' marked as __forceinline not inlined
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>
34 namespace boost { namespace proto
36 /// \brief Wrap \c PrimitiveTransform so that <tt>when\<\></tt> knows
37 /// it is callable. Requires that the parameter is actually a
38 /// PrimitiveTransform.
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.
46 /// template<typename Grammar>
49 /// unary_plus<Grammar>
50 /// , Grammar(_child) // May or may not work.
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
63 /// template<typename Grammar>
66 /// unary_plus<Grammar>
67 /// , call<Grammar>(_child) // OK, this works
72 /// The above could also have been written as:
75 /// template<typename Grammar>
78 /// unary_plus<Grammar>
79 /// , call<Grammar(_child)> // OK, this works, too
83 template<typename PrimitiveTransform>
88 /// \brief A specialization that treats function pointer Transforms as
89 /// if they were function type Transforms.
91 /// This specialization requires that \c Fun is actually a function type.
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
100 template<typename Fun>
106 template<typename Fun>
107 struct call<detail::msvc_fun_workaround<Fun> >
111 /// \brief Either call the PolymorphicFunctionObject with 0
112 /// arguments, or invoke the PrimitiveTransform with 3
114 template<typename Fun>
115 struct call<Fun()> : transform<call<Fun()> >
118 template<typename Expr, typename State, typename Data, bool B>
120 : transform_impl<Expr, State, Data>
122 typedef typename BOOST_PROTO_RESULT_OF<Fun()>::type result_type;
125 result_type operator()(
126 typename impl2::expr_param
127 , typename impl2::state_param
128 , typename impl2::data_param
136 template<typename Expr, typename State, typename Data>
137 struct impl2<Expr, State, Data, true>
138 : Fun::template impl<Expr, State, Data>
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.
145 /// If \c Fun is a nullary PolymorphicFunctionObject, return <tt>Fun()()</tt>.
146 /// Otherwise, return <tt>Fun()(e, s, d)</tt>.
148 /// \param e The current expression
149 /// \param s The current state
150 /// \param d An arbitrary data
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>
157 : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
161 /// \brief Either call the PolymorphicFunctionObject with 1
162 /// argument, or invoke the PrimitiveTransform with 3
164 template<typename Fun, typename A0>
165 struct call<Fun(A0)> : transform<call<Fun(A0)> >
167 template<typename Expr, typename State, typename Data, bool B>
169 : transform_impl<Expr, State, Data>
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;
175 result_type operator ()(
176 typename impl2::expr_param e
177 , typename impl2::state_param s
178 , typename impl2::data_param d
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))
187 template<typename Expr, typename State, typename Data>
188 struct impl2<Expr, State, Data, true>
189 : transform_impl<Expr, State, Data>
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;
195 result_type operator ()(
196 typename impl2::expr_param e
197 , typename impl2::state_param s
198 , typename impl2::data_param d
201 return typename Fun::template impl<a0, State, Data>()(
202 typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d)
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>.
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
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>.
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>
230 : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
234 /// \brief Either call the PolymorphicFunctionObject with 2
235 /// arguments, or invoke the PrimitiveTransform with 3
237 template<typename Fun, typename A0, typename A1>
238 struct call<Fun(A0, A1)> : transform<call<Fun(A0, A1)> >
240 template<typename Expr, typename State, typename Data, bool B>
242 : transform_impl<Expr, State, Data>
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;
249 result_type operator ()(
250 typename impl2::expr_param e
251 , typename impl2::state_param s
252 , typename impl2::data_param d
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))
262 template<typename Expr, typename State, typename Data>
263 struct impl2<Expr, State, Data, true>
264 : transform_impl<Expr, State, Data>
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;
271 result_type operator ()(
272 typename impl2::expr_param e
273 , typename impl2::state_param s
274 , typename impl2::data_param d
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)
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>.
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.
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>.
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>
312 : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
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)> >
323 template<typename Expr, typename State, typename Data, bool B>
325 : transform_impl<Expr, State, Data>
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;
333 result_type operator ()(
334 typename impl2::expr_param e
335 , typename impl2::state_param s
336 , typename impl2::data_param d
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))
347 template<typename Expr, typename State, typename Data>
348 struct impl2<Expr, State, Data, true>
349 : transform_impl<Expr, State, Data>
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;
357 result_type operator ()(
358 typename impl2::expr_param e
359 , typename impl2::state_param s
360 , typename impl2::data_param d
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)
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>.
376 /// \param e The current expression
377 /// \param s The current state
378 /// \param d An arbitrary data
380 template<typename Expr, typename State, typename Data>
382 : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
386 #include <boost/proto/transform/detail/call.hpp>
390 template<typename Fun>
391 struct is_callable<call<Fun> >
395 }} // namespace boost::proto
397 #if defined(_MSC_VER)
398 # pragma warning(pop)