1 //  return_type_traits.hpp -- Boost Lambda Library ---------------------------
2 
3 // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // For more information, see www.boost.org
10 
11 
12 #ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
13 #define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
14 
15 #include "boost/mpl/has_xxx.hpp"
16 
17 #include <cstddef> // needed for the ptrdiff_t
18 
19 namespace boost {
20 namespace lambda {
21 
22 // Much of the type deduction code for standard arithmetic types
23 // from Gary Powell
24 
25   // different arities:
26 template <class Act, class A1> struct return_type_1; // 1-ary actions
27 template <class Act, class A1, class A2> struct return_type_2; // 2-ary
28 template <class Act, class Args> struct return_type_N; // >3- ary
29 
30 template <class Act, class A1> struct return_type_1_prot;
31 template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary
32 template <class Act, class A1> struct return_type_N_prot; // >3-ary
33 
34 
35 namespace detail {
36 
37 template<class> class return_type_deduction_failure {};
38 
39   // In some cases return type deduction should fail (an invalid lambda
40   // expression). Sometimes the lambda expression can be ok, the return type
41   // just is not deducible (user defined operators). Then return type deduction
42   // should never be entered at all, and the use of ret<> does this.
43   // However, for nullary lambda functors, return type deduction is always
44   // entered, and there seems to be no way around this.
45 
46   // (the return type is part of the prototype of the non-template
47   // operator()(). The prototype is instantiated, even though the body
48   // is not.)
49 
50   // So, in the case the return type deduction should fail, it should not
51   // fail directly, but rather result in a valid but wrong return type,
52   // causing a compile time error only if the function is really called.
53 
54 
55 
56 } // end detail
57 
58 
59 
60 // return_type_X_prot classes --------------------------------------------
61 // These classes are the first layer that gets instantiated from the
62 // lambda_functor_base sig templates. It will check whether
63 // the action is protectable and one of arguments is "protected" or its
64 // evaluation will otherwise result in another lambda functor.
65 // If this is a case, the result type will be another lambda functor.
66 
67 // The arguments are always non-reference types, except for comma action
68 // where the right argument can be a reference too. This is because it
69 // matters (in the builtin case) whether the argument is an lvalue or
70 // rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue
71 
72 template <class Act, class A> struct return_type_1_prot {
73 public:
74   typedef typename
75     detail::IF<
76       is_protectable<Act>::value && is_lambda_functor<A>::value,
77       lambda_functor<
78         lambda_functor_base<
79           Act,
80           tuple<typename detail::remove_reference_and_cv<A>::type>
81         >
82       >,
83       typename return_type_1<Act, A>::type
84     >::RET type;
85 };
86 
87   // take care of the unavoidable instantiation for nullary case
88 template<class Act> struct return_type_1_prot<Act, null_type> {
89   typedef null_type type;
90 };
91 
92 // Unary actions (result from unary operators)
93 // do not have a default return type.
94 template<class Act, class A> struct return_type_1 {
95    typedef typename
96      detail::return_type_deduction_failure<return_type_1> type;
97 };
98 
99 
100 namespace detail {
101 
102   template <class T>
103   class protect_conversion {
104       typedef typename boost::remove_reference<T>::type non_ref_T;
105     public:
106 
107   // add const to rvalues, so that all rvalues are stored as const in
108   // the args tuple
109     typedef typename detail::IF_type<
110       boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value,
111       detail::identity_mapping<T>,
112       const_copy_argument<non_ref_T> // handles funtion and array
113     >::type type;                      // types correctly
114   };
115 
116 } // end detail
117 
118 template <class Act, class A, class B> struct return_type_2_prot {
119 
120 // experimental feature
121   // We may have a lambda functor as a result type of a subexpression
122   // (if protect) has  been used.
123   // Thus, if one of the parameter types is a lambda functor, the result
124   // is a lambda functor as well.
125   // We need to make a conservative choise here.
126   // The resulting lambda functor stores all const reference arguments as
127   // const copies. References to non-const are stored as such.
128   // So if the source of the argument is a const open argument, a bound
129   // argument stored as a const reference, or a function returning a
130   // const reference, that information is lost. There is no way of
131   // telling apart 'real const references' from just 'LL internal
132   // const references' (or it would be really hard)
133 
134   // The return type is a subclass of lambda_functor, which has a converting
135   // copy constructor. It can copy any lambda functor, that has the same
136   // action type and code, and a copy compatible argument tuple.
137 
138 
139   typedef typename boost::remove_reference<A>::type non_ref_A;
140   typedef typename boost::remove_reference<B>::type non_ref_B;
141 
142 typedef typename
143   detail::IF<
144     is_protectable<Act>::value &&
145       (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
146     lambda_functor<
147       lambda_functor_base<
148         Act,
149         tuple<typename detail::protect_conversion<A>::type,
150               typename detail::protect_conversion<B>::type>
151       >
152     >,
153     typename return_type_2<Act, non_ref_A, non_ref_B>::type
154   >::RET type;
155 };
156 
157   // take care of the unavoidable instantiation for nullary case
158 template<class Act> struct return_type_2_prot<Act, null_type, null_type> {
159   typedef null_type type;
160 };
161   // take care of the unavoidable instantiation for nullary case
162 template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> {
163   typedef null_type type;
164 };
165   // take care of the unavoidable instantiation for nullary case
166 template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> {
167   typedef null_type type;
168 };
169 
170   // comma is a special case, as the user defined operator can return
171   // an lvalue (reference) too, hence it must be handled at this level.
172 template<class A, class B>
173 struct return_type_2_comma
174 {
175   typedef typename boost::remove_reference<A>::type non_ref_A;
176   typedef typename boost::remove_reference<B>::type non_ref_B;
177 
178 typedef typename
179   detail::IF<
180     is_protectable<other_action<comma_action> >::value && // it is protectable
181     (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
182     lambda_functor<
183       lambda_functor_base<
184         other_action<comma_action>,
185         tuple<typename detail::protect_conversion<A>::type,
186               typename detail::protect_conversion<B>::type>
187       >
188     >,
189     typename
190       return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type
191   >::RET type1;
192 
193    // if no user defined return_type_2 (or plain_return_type_2) specialization
194   // matches, then return the righthand argument
195   typedef typename
196     detail::IF<
197       boost::is_same<type1, detail::unspecified>::value,
198       B,
199       type1
200     >::RET type;
201 
202 };
203 
204 
205   // currently there are no protectable actions with > 2 args
206 
207 template<class Act, class Args> struct return_type_N_prot {
208   typedef typename return_type_N<Act, Args>::type type;
209 };
210 
211   // take care of the unavoidable instantiation for nullary case
212 template<class Act> struct return_type_N_prot<Act, null_type> {
213   typedef null_type type;
214 };
215 
216 // handle different kind of actions ------------------------
217 
218   // use the return type given in the bind invocation as bind<Ret>(...)
219 template<int I, class Args, class Ret>
220 struct return_type_N<function_action<I, Ret>, Args> {
221   typedef Ret type;
222 };
223 
224 // ::result_type support
225 
226 namespace detail
227 {
228 
229 BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
230 
231 template<class F> struct get_result_type
232 {
233   typedef typename F::result_type type;
234 };
235 
236 template<class F, class A> struct get_sig
237 {
238   typedef typename function_adaptor<F>::template sig<A>::type type;
239 };
240 
241 } // namespace detail
242 
243   // Ret is detail::unspecified, so try to deduce return type
244 template<int I, class Args>
245 struct return_type_N<function_action<I, detail::unspecified>, Args > {
246 
247   // in the case of function action, the first element in Args is
248   // some type of function
249   typedef typename Args::head_type Func;
250   typedef typename detail::remove_reference_and_cv<Func>::type plain_Func;
251 
252 public:
253   // pass the function to function_adaptor, and get the return type from
254   // that
255   typedef typename detail::IF<
256     detail::has_result_type<plain_Func>::value,
257     detail::get_result_type<plain_Func>,
258     detail::get_sig<plain_Func, Args>
259   >::RET::type type;
260 };
261 
262 
263 } // namespace lambda
264 } // namespace boost
265 
266 #endif
267 
268 
269 
270