]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |