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
19namespace boost {
20namespace lambda {
21
22// Much of the type deduction code for standard arithmetic types
23// from Gary Powell
24
25 // different arities:
26template <class Act, class A1> struct return_type_1; // 1-ary actions
27template <class Act, class A1, class A2> struct return_type_2; // 2-ary
28template <class Act, class Args> struct return_type_N; // >3- ary
29
30template <class Act, class A1> struct return_type_1_prot;
31template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary
32template <class Act, class A1> struct return_type_N_prot; // >3-ary
33
34
35namespace detail {
36
37template<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
72template <class Act, class A> struct return_type_1_prot {
73public:
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
88template<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.
94template<class Act, class A> struct return_type_1 {
95 typedef typename
96 detail::return_type_deduction_failure<return_type_1> type;
97};
98
99
100namespace 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
118template <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
142typedef 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
158template<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
162template<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
166template<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.
172template<class A, class B>
173struct 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
178typedef 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
207template<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
212template<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>(...)
219template<int I, class Args, class Ret>
220struct return_type_N<function_action<I, Ret>, Args> {
221 typedef Ret type;
222};
223
224// ::result_type support
225
226namespace detail
227{
228
229BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
230
231template<class F> struct get_result_type
232{
233 typedef typename F::result_type type;
234};
235
236template<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
244template<int I, class Args>
245struct 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
252public:
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