1/*=============================================================================
2 Copyright (c) 2001-2007 Joel de Guzman
3 Copyright (c) 2015 Kohei Takahashi
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7==============================================================================*/
8
9#ifndef BOOST_PHOENIX_CORE_DETAIL_FUNCTION_EVAL_HPP
10#define BOOST_PHOENIX_CORE_DETAIL_FUNCTION_EVAL_HPP
11
12#include <boost/phoenix/core/limits.hpp>
13#include <boost/phoenix/support/iterate.hpp>
14#include <boost/phoenix/core/call.hpp>
15#include <boost/phoenix/core/expression.hpp>
16#include <boost/phoenix/core/meta_grammar.hpp>
17#include <boost/utility/result_of.hpp>
18
19#ifndef BOOST_PHOENIX_NO_VARIADIC_FUNCTION_EVAL
20# include <boost/mpl/if.hpp>
21# include <boost/type_traits/is_reference.hpp>
22#endif
23
24#ifdef BOOST_PHOENIX_NO_VARIADIC_EXPRESSION
25# include <boost/phoenix/core/detail/cpp03/function_eval_expr.hpp>
26#else
27BOOST_PHOENIX_DEFINE_EXPRESSION_VARARG(
28 (boost)(phoenix)(detail)(function_eval)
29 , (meta_grammar)(meta_grammar)
30 , _
31)
32#endif
33
34namespace boost { namespace phoenix {
35 namespace detail
36 {
37 template <typename T>
38 T& help_rvalue_deduction(T& x)
39 {
40 return x;
41 }
42
43 template <typename T>
44 T const& help_rvalue_deduction(T const& x)
45 {
46 return x;
47 }
48
49 struct function_eval
50 {
51 template <typename Sig>
52 struct result;
53
54#ifdef BOOST_PHOENIX_NO_VARIADIC_FUNCTION_EVAL
55 template <typename This, typename F, typename Context>
56 struct result<This(F, Context)>
57 {
58 typedef typename
59 remove_reference<
60 typename boost::result_of<evaluator(F, Context)>::type
61 >::type
62 fn;
63
64 typedef typename boost::result_of<fn()>::type type;
65 };
66
67 template <typename F, typename Context>
68 typename result<function_eval(F const&, Context const&)>::type
69 operator()(F const & f, Context const & ctx) const
70 {
71 return boost::phoenix::eval(f, ctx)();
72 }
73
74 template <typename F, typename Context>
75 typename result<function_eval(F &, Context const&)>::type
76 operator()(F & f, Context const & ctx) const
77 {
78 return boost::phoenix::eval(f, ctx)();
79 }
80
81 #include <boost/phoenix/core/detail/cpp03/function_eval.hpp>
82#else
83 template <typename, typename, typename...> struct result_impl;
84
85 template <typename F, typename... A, typename Head, typename... Tail>
86 struct result_impl<F, void(A...), Head, Tail...>
87 : result_impl<F, void(A..., Head), Tail...>
88 {
89 };
90
91 template <typename F, typename... A, typename Context>
92 struct result_impl<F, void(A...), Context>
93 {
94 typedef typename
95 remove_reference<
96 typename boost::result_of<evaluator(F, Context)>::type
97 >::type
98 fn;
99
100 template <typename T>
101 struct result_of_evaluator
102 {
103 typedef typename boost::add_reference<
104 typename boost::add_const<
105 typename boost::result_of<
106 boost::phoenix::evaluator(T, Context)
107 >::type
108 >::type
109 >::type type;
110 };
111
112 typedef typename
113 boost::result_of<
114 fn(typename result_of_evaluator<A>::type...)
115 >::type
116 type;
117
118 static type call(F f, A... a, Context ctx)
119 {
120 return boost::phoenix::eval(f, ctx)(help_rvalue_deduction(boost::phoenix::eval(a, ctx))...);
121 }
122 };
123
124 template <typename This, typename F, typename... A>
125 struct result<This(F, A...)>
126 : result_impl<F, void(), A...>
127 {
128 };
129
130 template <typename F, typename... A>
131 typename result<
132 function_eval(
133 F const &
134 , typename mpl::if_<is_reference<A>, A, A const &>::type...
135 )
136 >::type
137 // 'A &... a, Context const &ctx' doesn't work as intended: type deduction always fail.
138 operator()(F && f, A &&... a) const
139 {
140 return
141 result<
142 function_eval(
143 typename mpl::if_<is_reference<F>, F, F const &>::type
144 , typename mpl::if_<is_reference<A>, A, A const &>::type...
145 )
146 >::call(f, a...);
147 }
148#endif
149 };
150
151 }
152
153 template <typename Dummy>
154 struct default_actions::when<detail::rule::function_eval, Dummy>
155 : phoenix::call<detail::function_eval>
156 {};
157}}
158
159#endif
160