7d87c906d60055d65713d3352d63382c6085b226
[platform/upstream/boost.git] / boost / proto / transform / call.hpp
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
9 #ifndef BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007
10 #define BOOST_PROTO_TRANSFORM_CALL_HPP_EAN_11_02_2007
11
12 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
13 # pragma warning(push)
14 # pragma warning(disable: 4714) // function 'xxx' marked as __forceinline not inlined
15 #endif
16
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>
33
34 namespace boost { namespace proto
35 {
36     /// \brief Wrap \c PrimitiveTransform so that <tt>when\<\></tt> knows
37     /// it is callable. Requires that the parameter is actually a
38     /// PrimitiveTransform.
39     ///
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.
44     ///
45     /// \code
46     /// template<typename Grammar>
47     /// struct Foo
48     ///   : when<
49     ///         unary_plus<Grammar>
50     ///       , Grammar(_child)   // May or may not work.
51     ///     >
52     /// {};
53     /// \endcode
54     ///
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
60     /// as:
61     ///
62     /// \code
63     /// template<typename Grammar>
64     /// struct Foo
65     ///   : when<
66     ///         unary_plus<Grammar>
67     ///       , call<Grammar>(_child)   // OK, this works
68     ///     >
69     /// {};
70     /// \endcode
71     ///
72     /// The above could also have been written as:
73     ///
74     /// \code
75     /// template<typename Grammar>
76     /// struct Foo
77     ///   : when<
78     ///         unary_plus<Grammar>
79     ///       , call<Grammar(_child)>   // OK, this works, too
80     ///     >
81     /// {};
82     /// \endcode
83     template<typename PrimitiveTransform>
84     struct call
85       : PrimitiveTransform
86     {};
87
88     /// \brief A specialization that treats function pointer Transforms as
89     /// if they were function type Transforms.
90     ///
91     /// This specialization requires that \c Fun is actually a function type.
92     ///
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
99     /// properly.
100     template<typename Fun>
101     struct call<Fun *>
102       : call<Fun>
103     {};
104
105     /// INTERNAL ONLY
106     template<typename Fun>
107     struct call<detail::msvc_fun_workaround<Fun> >
108       : call<Fun>
109     {};
110
111     /// \brief Either call the PolymorphicFunctionObject with 0
112     /// arguments, or invoke the PrimitiveTransform with 3
113     /// arguments.
114     template<typename Fun>
115     struct call<Fun()> : transform<call<Fun()> >
116     {
117         /// INTERNAL ONLY
118         template<typename Expr, typename State, typename Data, bool B>
119         struct impl2
120           : transform_impl<Expr, State, Data>
121         {
122             typedef typename BOOST_PROTO_RESULT_OF<Fun()>::type result_type;
123
124             BOOST_FORCEINLINE
125             result_type operator()(
126                 typename impl2::expr_param
127               , typename impl2::state_param
128               , typename impl2::data_param
129             ) const
130             {
131                 return Fun()();
132             }
133         };
134
135         /// INTERNAL ONLY
136         template<typename Expr, typename State, typename Data>
137         struct impl2<Expr, State, Data, true>
138           : Fun::template impl<Expr, State, Data>
139         {};
140
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.
144         ///
145         /// If \c Fun is a nullary PolymorphicFunctionObject, return <tt>Fun()()</tt>.
146         /// Otherwise, return <tt>Fun()(e, s, d)</tt>.
147         ///
148         /// \param e The current expression
149         /// \param s The current state
150         /// \param d An arbitrary data
151
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>
156         struct impl
157           : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
158         {};
159     };
160
161     /// \brief Either call the PolymorphicFunctionObject with 1
162     /// argument, or invoke the PrimitiveTransform with 3
163     /// arguments.
164     template<typename Fun, typename A0>
165     struct call<Fun(A0)> : transform<call<Fun(A0)> >
166     {
167         template<typename Expr, typename State, typename Data, bool B>
168         struct impl2
169           : transform_impl<Expr, State, Data>
170         {
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;
173             
174             BOOST_FORCEINLINE
175             result_type operator ()(
176                 typename impl2::expr_param   e
177               , typename impl2::state_param  s
178               , typename impl2::data_param   d
179             ) const
180             {
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))
183                 );
184             }
185         };
186
187         template<typename Expr, typename State, typename Data>
188         struct impl2<Expr, State, Data, true>
189           : transform_impl<Expr, State, Data>
190         {
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;
193             
194             BOOST_FORCEINLINE
195             result_type operator ()(
196                 typename impl2::expr_param   e
197               , typename impl2::state_param  s
198               , typename impl2::data_param   d
199             ) const
200             {
201                 return typename Fun::template impl<a0, State, Data>()(
202                     typename when<_, A0>::template impl<Expr, State, Data>()(e, s, d)
203                   , s
204                   , d
205                 );
206             }
207         };
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>.
213
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
218         /// data.
219         ///
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>.
224         ///
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>
229         struct impl
230           : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
231         {};
232     };
233
234     /// \brief Either call the PolymorphicFunctionObject with 2
235     /// arguments, or invoke the PrimitiveTransform with 3
236     /// arguments.
237     template<typename Fun, typename A0, typename A1>
238     struct call<Fun(A0, A1)> : transform<call<Fun(A0, A1)> >
239     {
240         template<typename Expr, typename State, typename Data, bool B>
241         struct impl2
242           : transform_impl<Expr, State, Data>
243         {
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;
247             
248             BOOST_FORCEINLINE
249             result_type operator ()(
250                 typename impl2::expr_param   e
251               , typename impl2::state_param  s
252               , typename impl2::data_param   d
253             ) const
254             {
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))
258                 );
259             }
260         };
261
262         template<typename Expr, typename State, typename Data>
263         struct impl2<Expr, State, Data, true>
264           : transform_impl<Expr, State, Data>
265         {
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;
269             
270             BOOST_FORCEINLINE
271             result_type operator ()(
272                 typename impl2::expr_param   e
273               , typename impl2::state_param  s
274               , typename impl2::data_param   d
275             ) const
276             {
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)
280                   , d
281                 );
282             }
283         };
284
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>.
293
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.
300         ///
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>.
306         ///
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>
311         struct impl
312           : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
313         {};
314     };
315
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)> >
322     {
323         template<typename Expr, typename State, typename Data, bool B>
324         struct impl2
325           : transform_impl<Expr, State, Data>
326         {
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;
331             
332             BOOST_FORCEINLINE
333             result_type operator ()(
334                 typename impl2::expr_param   e
335               , typename impl2::state_param  s
336               , typename impl2::data_param   d
337             ) const
338             {
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))
343                 );
344             }
345         };
346
347         template<typename Expr, typename State, typename Data>
348         struct impl2<Expr, State, Data, true>
349           : transform_impl<Expr, State, Data>
350         {
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;
355             
356             BOOST_FORCEINLINE
357             result_type operator ()(
358                 typename impl2::expr_param   e
359               , typename impl2::state_param  s
360               , typename impl2::data_param   d
361             ) const
362             {
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)
367                 );
368             }
369         };
370
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>.
375         ///
376         /// \param e The current expression
377         /// \param s The current state
378         /// \param d An arbitrary data
379
380         template<typename Expr, typename State, typename Data>
381         struct impl
382           : impl2<Expr, State, Data, detail::is_transform_<Fun>::value>
383         {};
384     };
385
386     #include <boost/proto/transform/detail/call.hpp>
387
388     /// INTERNAL ONLY
389     ///
390     template<typename Fun>
391     struct is_callable<call<Fun> >
392       : mpl::true_
393     {};
394
395 }} // namespace boost::proto
396
397 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
398 # pragma warning(pop)
399 #endif
400
401 #endif