]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost Lambda Library ret.hpp ----------------------------------------- |
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_RET_HPP | |
13 | #define BOOST_LAMBDA_RET_HPP | |
14 | ||
15 | namespace boost { | |
16 | namespace lambda { | |
17 | ||
18 | // TODO: | |
19 | ||
20 | // Add specializations for function references for ret, protect and unlambda | |
21 | // e.g void foo(); unlambda(foo); fails, as it would add a const qualifier | |
22 | // for a function type. | |
23 | // on the other hand unlambda(*foo) does work | |
24 | ||
25 | ||
26 | // -- ret ------------------------- | |
27 | // the explicit return type template | |
28 | ||
29 | // TODO: It'd be nice to make ret a nop for other than lambda functors | |
30 | // but causes an ambiguiyty with gcc (not with KCC), check what is the | |
31 | // right interpretation. | |
32 | ||
33 | // // ret for others than lambda functors has no effect | |
34 | // template <class U, class T> | |
35 | // inline const T& ret(const T& t) { return t; } | |
36 | ||
37 | ||
38 | template<class RET, class Arg> | |
39 | inline const | |
40 | lambda_functor< | |
41 | lambda_functor_base< | |
42 | explicit_return_type_action<RET>, | |
43 | tuple<lambda_functor<Arg> > | |
44 | > | |
45 | > | |
46 | ret(const lambda_functor<Arg>& a1) | |
47 | { | |
48 | return | |
49 | lambda_functor_base< | |
50 | explicit_return_type_action<RET>, | |
51 | tuple<lambda_functor<Arg> > | |
52 | > | |
53 | (tuple<lambda_functor<Arg> >(a1)); | |
54 | } | |
55 | ||
56 | // protect ------------------ | |
57 | ||
58 | // protecting others than lambda functors has no effect | |
59 | template <class T> | |
60 | inline const T& protect(const T& t) { return t; } | |
61 | ||
62 | template<class Arg> | |
63 | inline const | |
64 | lambda_functor< | |
65 | lambda_functor_base< | |
66 | protect_action, | |
67 | tuple<lambda_functor<Arg> > | |
68 | > | |
69 | > | |
70 | protect(const lambda_functor<Arg>& a1) | |
71 | { | |
72 | return | |
73 | lambda_functor_base< | |
74 | protect_action, | |
75 | tuple<lambda_functor<Arg> > | |
76 | > | |
77 | (tuple<lambda_functor<Arg> >(a1)); | |
78 | } | |
79 | ||
80 | // ------------------------------------------------------------------- | |
81 | ||
82 | // Hides the lambda functorness of a lambda functor. | |
83 | // After this, the functor is immune to argument substitution, etc. | |
84 | // This can be used, e.g. to make it safe to pass lambda functors as | |
85 | // arguments to functions, which might use them as target functions | |
86 | ||
87 | // note, unlambda and protect are different things. Protect hides the lambda | |
88 | // functor for one application, unlambda for good. | |
89 | ||
90 | template <class LambdaFunctor> | |
91 | class non_lambda_functor | |
92 | { | |
93 | LambdaFunctor lf; | |
94 | public: | |
95 | ||
96 | // This functor defines the result_type typedef. | |
97 | // The result type must be deducible without knowing the arguments | |
98 | ||
99 | template <class SigArgs> struct sig { | |
100 | typedef typename | |
101 | LambdaFunctor::inherited:: | |
102 | template sig<typename SigArgs::tail_type>::type type; | |
103 | }; | |
104 | ||
105 | explicit non_lambda_functor(const LambdaFunctor& a) : lf(a) {} | |
106 | ||
107 | typename LambdaFunctor::nullary_return_type | |
108 | operator()() const { | |
109 | return lf.template | |
110 | call<typename LambdaFunctor::nullary_return_type> | |
111 | (cnull_type(), cnull_type(), cnull_type(), cnull_type()); | |
112 | } | |
113 | ||
114 | template<class A> | |
115 | typename sig<tuple<const non_lambda_functor, A&> >::type | |
116 | operator()(A& a) const { | |
117 | return lf.template call<typename sig<tuple<const non_lambda_functor, A&> >::type >(a, cnull_type(), cnull_type(), cnull_type()); | |
118 | } | |
119 | ||
120 | template<class A, class B> | |
121 | typename sig<tuple<const non_lambda_functor, A&, B&> >::type | |
122 | operator()(A& a, B& b) const { | |
123 | return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&> >::type >(a, b, cnull_type(), cnull_type()); | |
124 | } | |
125 | ||
126 | template<class A, class B, class C> | |
127 | typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type | |
128 | operator()(A& a, B& b, C& c) const { | |
129 | return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type>(a, b, c, cnull_type()); | |
130 | } | |
131 | }; | |
132 | ||
133 | template <class Arg> | |
134 | inline const Arg& unlambda(const Arg& a) { return a; } | |
135 | ||
136 | template <class Arg> | |
137 | inline const non_lambda_functor<lambda_functor<Arg> > | |
138 | unlambda(const lambda_functor<Arg>& a) | |
139 | { | |
140 | return non_lambda_functor<lambda_functor<Arg> >(a); | |
141 | } | |
142 | ||
143 | // Due to a language restriction, lambda functors cannot be made to | |
144 | // accept non-const rvalue arguments. Usually iterators do not return | |
145 | // temporaries, but sometimes they do. That's why a workaround is provided. | |
146 | // Note, that this potentially breaks const correctness, so be careful! | |
147 | ||
148 | // any lambda functor can be turned into a const_incorrect_lambda_functor | |
149 | // The operator() takes arguments as consts and then casts constness | |
150 | // away. So this breaks const correctness!!! but is a necessary workaround | |
151 | // in some cases due to language limitations. | |
152 | // Note, that this is not a lambda_functor anymore, so it can not be used | |
153 | // as a sub lambda expression. | |
154 | ||
155 | template <class LambdaFunctor> | |
156 | struct const_incorrect_lambda_functor { | |
157 | LambdaFunctor lf; | |
158 | public: | |
159 | ||
160 | explicit const_incorrect_lambda_functor(const LambdaFunctor& a) : lf(a) {} | |
161 | ||
162 | template <class SigArgs> struct sig { | |
163 | typedef typename | |
164 | LambdaFunctor::inherited::template | |
165 | sig<typename SigArgs::tail_type>::type type; | |
166 | }; | |
167 | ||
168 | // The nullary case is not needed (no arguments, no parameter type problems) | |
169 | ||
170 | template<class A> | |
171 | typename sig<tuple<const const_incorrect_lambda_functor, A&> >::type | |
172 | operator()(const A& a) const { | |
173 | return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&> >::type >(const_cast<A&>(a), cnull_type(), cnull_type(), cnull_type()); | |
174 | } | |
175 | ||
176 | template<class A, class B> | |
177 | typename sig<tuple<const const_incorrect_lambda_functor, A&, B&> >::type | |
178 | operator()(const A& a, const B& b) const { | |
179 | return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&, B&> >::type >(const_cast<A&>(a), const_cast<B&>(b), cnull_type(), cnull_type()); | |
180 | } | |
181 | ||
182 | template<class A, class B, class C> | |
183 | typename sig<tuple<const const_incorrect_lambda_functor, A&, B&, C&> >::type | |
184 | operator()(const A& a, const B& b, const C& c) const { | |
185 | return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&, B&, C&> >::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c), cnull_type()); | |
186 | } | |
187 | }; | |
188 | ||
189 | // ------------------------------------------------------------------------ | |
190 | // any lambda functor can be turned into a const_parameter_lambda_functor | |
191 | // The operator() takes arguments as const. | |
192 | // This is useful if lambda functors are called with non-const rvalues. | |
193 | // Note, that this is not a lambda_functor anymore, so it can not be used | |
194 | // as a sub lambda expression. | |
195 | ||
196 | template <class LambdaFunctor> | |
197 | struct const_parameter_lambda_functor { | |
198 | LambdaFunctor lf; | |
199 | public: | |
200 | ||
201 | explicit const_parameter_lambda_functor(const LambdaFunctor& a) : lf(a) {} | |
202 | ||
203 | template <class SigArgs> struct sig { | |
204 | typedef typename | |
205 | LambdaFunctor::inherited::template | |
206 | sig<typename SigArgs::tail_type>::type type; | |
207 | }; | |
208 | ||
209 | // The nullary case is not needed: no arguments, no constness problems. | |
210 | ||
211 | template<class A> | |
212 | typename sig<tuple<const const_parameter_lambda_functor, const A&> >::type | |
213 | operator()(const A& a) const { | |
214 | return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&> >::type >(a, cnull_type(), cnull_type(), cnull_type()); | |
215 | } | |
216 | ||
217 | template<class A, class B> | |
218 | typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&> >::type | |
219 | operator()(const A& a, const B& b) const { | |
220 | return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&> >::type >(a, b, cnull_type(), cnull_type()); | |
221 | } | |
222 | ||
223 | template<class A, class B, class C> | |
224 | typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&, const C&> | |
225 | >::type | |
226 | operator()(const A& a, const B& b, const C& c) const { | |
227 | return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&, const C&> >::type>(a, b, c, cnull_type()); | |
228 | } | |
229 | }; | |
230 | ||
231 | template <class Arg> | |
232 | inline const const_incorrect_lambda_functor<lambda_functor<Arg> > | |
233 | break_const(const lambda_functor<Arg>& lf) | |
234 | { | |
235 | return const_incorrect_lambda_functor<lambda_functor<Arg> >(lf); | |
236 | } | |
237 | ||
238 | ||
239 | template <class Arg> | |
240 | inline const const_parameter_lambda_functor<lambda_functor<Arg> > | |
241 | const_parameters(const lambda_functor<Arg>& lf) | |
242 | { | |
243 | return const_parameter_lambda_functor<lambda_functor<Arg> >(lf); | |
244 | } | |
245 | ||
246 | // make void ------------------------------------------------ | |
247 | // make_void( x ) turns a lambda functor x with some return type y into | |
248 | // another lambda functor, which has a void return type | |
249 | // when called, the original return type is discarded | |
250 | ||
251 | // we use this action. The action class will be called, which means that | |
252 | // the wrapped lambda functor is evaluated, but we just don't do anything | |
253 | // with the result. | |
254 | struct voidifier_action { | |
255 | template<class Ret, class A> static void apply(A&) {} | |
256 | }; | |
257 | ||
258 | template<class Args> struct return_type_N<voidifier_action, Args> { | |
259 | typedef void type; | |
260 | }; | |
261 | ||
262 | template<class Arg1> | |
263 | inline const | |
264 | lambda_functor< | |
265 | lambda_functor_base< | |
266 | action<1, voidifier_action>, | |
267 | tuple<lambda_functor<Arg1> > | |
268 | > | |
269 | > | |
270 | make_void(const lambda_functor<Arg1>& a1) { | |
271 | return | |
272 | lambda_functor_base< | |
273 | action<1, voidifier_action>, | |
274 | tuple<lambda_functor<Arg1> > | |
275 | > | |
276 | (tuple<lambda_functor<Arg1> > (a1)); | |
277 | } | |
278 | ||
279 | // for non-lambda functors, make_void does nothing | |
280 | // (the argument gets evaluated immediately) | |
281 | ||
282 | template<class Arg1> | |
283 | inline const | |
284 | lambda_functor< | |
285 | lambda_functor_base<do_nothing_action, null_type> | |
286 | > | |
287 | make_void(const Arg1&) { | |
288 | return | |
289 | lambda_functor_base<do_nothing_action, null_type>(); | |
290 | } | |
291 | ||
292 | // std_functor ----------------------------------------------------- | |
293 | ||
294 | // The STL uses the result_type typedef as the convention to let binders know | |
295 | // the return type of a function object. | |
296 | // LL uses the sig template. | |
297 | // To let LL know that the function object has the result_type typedef | |
298 | // defined, it can be wrapped with the std_functor function. | |
299 | ||
300 | ||
301 | // Just inherit form the template parameter (the standard functor), | |
302 | // and provide a sig template. So we have a class which is still the | |
303 | // same functor + the sig template. | |
304 | ||
305 | template<class T> | |
306 | struct result_type_to_sig : public T { | |
307 | template<class Args> struct sig { typedef typename T::result_type type; }; | |
308 | result_type_to_sig(const T& t) : T(t) {} | |
309 | }; | |
310 | ||
311 | template<class F> | |
312 | inline result_type_to_sig<F> std_functor(const F& f) { return f; } | |
313 | ||
314 | ||
315 | } // namespace lambda | |
316 | } // namespace boost | |
317 | ||
318 | #endif | |
319 | ||
320 | ||
321 | ||
322 | ||
323 | ||
324 | ||
325 |