1 | // - lambda_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_LAMBDA_TRAITS_HPP |
13 | #define BOOST_LAMBDA_LAMBDA_TRAITS_HPP |
14 | |
15 | #include "boost/type_traits/transform_traits.hpp" |
16 | #include "boost/type_traits/cv_traits.hpp" |
17 | #include "boost/type_traits/function_traits.hpp" |
18 | #include "boost/type_traits/object_traits.hpp" |
19 | #include "boost/tuple/tuple.hpp" |
20 | |
21 | namespace boost { |
22 | namespace lambda { |
23 | |
24 | // -- if construct ------------------------------------------------ |
25 | // Proposed by Krzysztof Czarnecki and Ulrich Eisenecker |
26 | |
27 | namespace detail { |
28 | |
29 | template <bool If, class Then, class Else> struct IF { typedef Then RET; }; |
30 | |
31 | template <class Then, class Else> struct IF<false, Then, Else> { |
32 | typedef Else RET; |
33 | }; |
34 | |
35 | |
36 | // An if construct that doesn't instantiate the non-matching template: |
37 | |
38 | // Called as: |
39 | // IF_type<condition, A, B>::type |
40 | // The matching template must define the typeded 'type' |
41 | // I.e. A::type if condition is true, B::type if condition is false |
42 | // Idea from Vesa Karvonen (from C&E as well I guess) |
43 | template<class T> |
44 | struct IF_type_ |
45 | { |
46 | typedef typename T::type type; |
47 | }; |
48 | |
49 | |
50 | template<bool C, class T, class E> |
51 | struct IF_type |
52 | { |
53 | typedef typename |
54 | IF_type_<typename IF<C, T, E>::RET >::type type; |
55 | }; |
56 | |
57 | // helper that can be used to give typedef T to some type |
58 | template <class T> struct identity_mapping { typedef T type; }; |
59 | |
60 | // An if construct for finding an integral constant 'value' |
61 | // Does not instantiate the non-matching branch |
62 | // Called as IF_value<condition, A, B>::value |
63 | // If condition is true A::value must be defined, otherwise B::value |
64 | |
65 | template<class T> |
66 | struct IF_value_ |
67 | { |
68 | BOOST_STATIC_CONSTANT(int, value = T::value); |
69 | }; |
70 | |
71 | |
72 | template<bool C, class T, class E> |
73 | struct IF_value |
74 | { |
75 | BOOST_STATIC_CONSTANT(int, value = (IF_value_<typename IF<C, T, E>::RET>::value)); |
76 | }; |
77 | |
78 | |
79 | // -------------------------------------------------------------- |
80 | |
81 | // removes reference from other than function types: |
82 | template<class T> class remove_reference_if_valid |
83 | { |
84 | |
85 | typedef typename boost::remove_reference<T>::type plainT; |
86 | public: |
87 | typedef typename IF< |
88 | boost::is_function<plainT>::value, |
89 | T, |
90 | plainT |
91 | >::RET type; |
92 | |
93 | }; |
94 | |
95 | |
96 | template<class T> struct remove_reference_and_cv { |
97 | typedef typename boost::remove_cv< |
98 | typename boost::remove_reference<T>::type |
99 | >::type type; |
100 | }; |
101 | |
102 | |
103 | |
104 | // returns a reference to the element of tuple T |
105 | template<int N, class T> struct tuple_element_as_reference { |
106 | typedef typename |
107 | boost::tuples::access_traits< |
108 | typename boost::tuples::element<N, T>::type |
109 | >::non_const_type type; |
110 | }; |
111 | |
112 | // returns the cv and reverence stripped type of a tuple element |
113 | template<int N, class T> struct tuple_element_stripped { |
114 | typedef typename |
115 | remove_reference_and_cv< |
116 | typename boost::tuples::element<N, T>::type |
117 | >::type type; |
118 | }; |
119 | |
120 | // is_lambda_functor ------------------------------------------------- |
121 | |
122 | template <class T> struct is_lambda_functor_ { |
123 | BOOST_STATIC_CONSTANT(bool, value = false); |
124 | }; |
125 | |
126 | template <class Arg> struct is_lambda_functor_<lambda_functor<Arg> > { |
127 | BOOST_STATIC_CONSTANT(bool, value = true); |
128 | }; |
129 | |
130 | } // end detail |
131 | |
132 | |
133 | template <class T> struct is_lambda_functor { |
134 | BOOST_STATIC_CONSTANT(bool, |
135 | value = |
136 | detail::is_lambda_functor_< |
137 | typename detail::remove_reference_and_cv<T>::type |
138 | >::value); |
139 | }; |
140 | |
141 | |
142 | namespace detail { |
143 | |
144 | // -- parameter_traits_ --------------------------------------------- |
145 | |
146 | // An internal parameter type traits class that respects |
147 | // the reference_wrapper class. |
148 | |
149 | // The conversions performed are: |
150 | // references -> compile_time_error |
151 | // T1 -> T2, |
152 | // reference_wrapper<T> -> T& |
153 | // const array -> ref to const array |
154 | // array -> ref to array |
155 | // function -> ref to function |
156 | |
157 | // ------------------------------------------------------------------------ |
158 | |
159 | template<class T1, class T2> |
160 | struct parameter_traits_ { |
161 | typedef T2 type; |
162 | }; |
163 | |
164 | // Do not instantiate with reference types |
165 | template<class T, class Any> struct parameter_traits_<T&, Any> { |
166 | typedef typename |
167 | generate_error<T&>:: |
168 | parameter_traits_class_instantiated_with_reference_type type; |
169 | }; |
170 | |
171 | // Arrays can't be stored as plain types; convert them to references |
172 | template<class T, int n, class Any> struct parameter_traits_<T[n], Any> { |
173 | typedef T (&type)[n]; |
174 | }; |
175 | |
176 | template<class T, int n, class Any> |
177 | struct parameter_traits_<const T[n], Any> { |
178 | typedef const T (&type)[n]; |
179 | }; |
180 | |
181 | template<class T, int n, class Any> |
182 | struct parameter_traits_<volatile T[n], Any> { |
183 | typedef volatile T (&type)[n]; |
184 | }; |
185 | template<class T, int n, class Any> |
186 | struct parameter_traits_<const volatile T[n], Any> { |
187 | typedef const volatile T (&type)[n]; |
188 | }; |
189 | |
190 | |
191 | template<class T, class Any> |
192 | struct parameter_traits_<boost::reference_wrapper<T>, Any >{ |
193 | typedef T& type; |
194 | }; |
195 | |
196 | template<class T, class Any> |
197 | struct parameter_traits_<const boost::reference_wrapper<T>, Any >{ |
198 | typedef T& type; |
199 | }; |
200 | |
201 | template<class T, class Any> |
202 | struct parameter_traits_<volatile boost::reference_wrapper<T>, Any >{ |
203 | typedef T& type; |
204 | }; |
205 | |
206 | template<class T, class Any> |
207 | struct parameter_traits_<const volatile boost::reference_wrapper<T>, Any >{ |
208 | typedef T& type; |
209 | }; |
210 | |
211 | template<class Any> |
212 | struct parameter_traits_<void, Any> { |
213 | typedef void type; |
214 | }; |
215 | |
216 | template<class Arg, class Any> |
217 | struct parameter_traits_<lambda_functor<Arg>, Any > { |
218 | typedef lambda_functor<Arg> type; |
219 | }; |
220 | |
221 | template<class Arg, class Any> |
222 | struct parameter_traits_<const lambda_functor<Arg>, Any > { |
223 | typedef lambda_functor<Arg> type; |
224 | }; |
225 | |
226 | // Are the volatile versions needed? |
227 | template<class Arg, class Any> |
228 | struct parameter_traits_<volatile lambda_functor<Arg>, Any > { |
229 | typedef lambda_functor<Arg> type; |
230 | }; |
231 | |
232 | template<class Arg, class Any> |
233 | struct parameter_traits_<const volatile lambda_functor<Arg>, Any > { |
234 | typedef lambda_functor<Arg> type; |
235 | }; |
236 | |
237 | } // end namespace detail |
238 | |
239 | |
240 | // ------------------------------------------------------------------------ |
241 | // traits classes for lambda expressions (bind functions, operators ...) |
242 | |
243 | // must be instantiated with non-reference types |
244 | |
245 | // The default is const plain type ------------------------- |
246 | // const T -> const T, |
247 | // T -> const T, |
248 | // references -> compile_time_error |
249 | // reference_wrapper<T> -> T& |
250 | // array -> const ref array |
251 | template<class T> |
252 | struct const_copy_argument { |
253 | typedef typename |
254 | detail::parameter_traits_< |
255 | T, |
256 | typename detail::IF<boost::is_function<T>::value, T&, const T>::RET |
257 | >::type type; |
258 | }; |
259 | |
260 | // T may be a function type. Without the IF test, const would be added |
261 | // to a function type, which is illegal. |
262 | |
263 | // all arrays are converted to const. |
264 | // This traits template is used for 'const T&' parameter passing |
265 | // and thus the knowledge of the potential |
266 | // non-constness of an actual argument is lost. |
267 | template<class T, int n> struct const_copy_argument <T[n]> { |
268 | typedef const T (&type)[n]; |
269 | }; |
270 | template<class T, int n> struct const_copy_argument <volatile T[n]> { |
271 | typedef const volatile T (&type)[n]; |
272 | }; |
273 | |
274 | template<class T> |
275 | struct const_copy_argument<T&> {}; |
276 | // do not instantiate with references |
277 | // typedef typename detail::generate_error<T&>::references_not_allowed type; |
278 | |
279 | |
280 | template<> |
281 | struct const_copy_argument<void> { |
282 | typedef void type; |
283 | }; |
284 | |
285 | template<> |
286 | struct const_copy_argument<void const> { |
287 | typedef void type; |
288 | }; |
289 | |
290 | |
291 | // Does the same as const_copy_argument, but passes references through as such |
292 | template<class T> |
293 | struct bound_argument_conversion { |
294 | typedef typename const_copy_argument<T>::type type; |
295 | }; |
296 | |
297 | template<class T> |
298 | struct bound_argument_conversion<T&> { |
299 | typedef T& type; |
300 | }; |
301 | |
302 | // The default is non-const reference ------------------------- |
303 | // const T -> const T&, |
304 | // T -> T&, |
305 | // references -> compile_time_error |
306 | // reference_wrapper<T> -> T& |
307 | template<class T> |
308 | struct reference_argument { |
309 | typedef typename detail::parameter_traits_<T, T&>::type type; |
310 | }; |
311 | |
312 | template<class T> |
313 | struct reference_argument<T&> { |
314 | typedef typename detail::generate_error<T&>::references_not_allowed type; |
315 | }; |
316 | |
317 | template<class Arg> |
318 | struct reference_argument<lambda_functor<Arg> > { |
319 | typedef lambda_functor<Arg> type; |
320 | }; |
321 | |
322 | template<class Arg> |
323 | struct reference_argument<const lambda_functor<Arg> > { |
324 | typedef lambda_functor<Arg> type; |
325 | }; |
326 | |
327 | // Are the volatile versions needed? |
328 | template<class Arg> |
329 | struct reference_argument<volatile lambda_functor<Arg> > { |
330 | typedef lambda_functor<Arg> type; |
331 | }; |
332 | |
333 | template<class Arg> |
334 | struct reference_argument<const volatile lambda_functor<Arg> > { |
335 | typedef lambda_functor<Arg> type; |
336 | }; |
337 | |
338 | template<> |
339 | struct reference_argument<void> { |
340 | typedef void type; |
341 | }; |
342 | |
343 | namespace detail { |
344 | |
345 | // Array to pointer conversion |
346 | template <class T> |
347 | struct array_to_pointer { |
348 | typedef T type; |
349 | }; |
350 | |
351 | template <class T, int N> |
352 | struct array_to_pointer <const T[N]> { |
353 | typedef const T* type; |
354 | }; |
355 | template <class T, int N> |
356 | struct array_to_pointer <T[N]> { |
357 | typedef T* type; |
358 | }; |
359 | |
360 | template <class T, int N> |
361 | struct array_to_pointer <const T (&) [N]> { |
362 | typedef const T* type; |
363 | }; |
364 | template <class T, int N> |
365 | struct array_to_pointer <T (&) [N]> { |
366 | typedef T* type; |
367 | }; |
368 | |
369 | |
370 | // --------------------------------------------------------------------------- |
371 | // The call_traits for bind |
372 | // Respects the reference_wrapper class. |
373 | |
374 | // These templates are used outside of bind functions as well. |
375 | // the bind_tuple_mapper provides a shorter notation for default |
376 | // bound argument storing semantics, if all arguments are treated |
377 | // uniformly. |
378 | |
379 | // from template<class T> foo(const T& t) : bind_traits<const T>::type |
380 | // from template<class T> foo(T& t) : bind_traits<T>::type |
381 | |
382 | // Conversions: |
383 | // T -> const T, |
384 | // cv T -> cv T, |
385 | // T& -> T& |
386 | // reference_wrapper<T> -> T& |
387 | // const reference_wrapper<T> -> T& |
388 | // array -> const ref array |
389 | |
390 | // make bound arguments const, this is a deliberate design choice, the |
391 | // purpose is to prevent side effects to bound arguments that are stored |
392 | // as copies |
393 | template<class T> |
394 | struct bind_traits { |
395 | typedef const T type; |
396 | }; |
397 | |
398 | template<class T> |
399 | struct bind_traits<T&> { |
400 | typedef T& type; |
401 | }; |
402 | |
403 | // null_types are an exception, we always want to store them as non const |
404 | // so that other templates can assume that null_type is always without const |
405 | template<> |
406 | struct bind_traits<null_type> { |
407 | typedef null_type type; |
408 | }; |
409 | |
410 | // the bind_tuple_mapper, bind_type_generators may |
411 | // introduce const to null_type |
412 | template<> |
413 | struct bind_traits<const null_type> { |
414 | typedef null_type type; |
415 | }; |
416 | |
417 | // Arrays can't be stored as plain types; convert them to references. |
418 | // All arrays are converted to const. This is because bind takes its |
419 | // parameters as const T& and thus the knowledge of the potential |
420 | // non-constness of actual argument is lost. |
421 | template<class T, int n> struct bind_traits <T[n]> { |
422 | typedef const T (&type)[n]; |
423 | }; |
424 | |
425 | template<class T, int n> |
426 | struct bind_traits<const T[n]> { |
427 | typedef const T (&type)[n]; |
428 | }; |
429 | |
430 | template<class T, int n> struct bind_traits<volatile T[n]> { |
431 | typedef const volatile T (&type)[n]; |
432 | }; |
433 | |
434 | template<class T, int n> |
435 | struct bind_traits<const volatile T[n]> { |
436 | typedef const volatile T (&type)[n]; |
437 | }; |
438 | |
439 | template<class R> |
440 | struct bind_traits<R()> { |
441 | typedef R(&type)(); |
442 | }; |
443 | |
444 | template<class R, class Arg1> |
445 | struct bind_traits<R(Arg1)> { |
446 | typedef R(&type)(Arg1); |
447 | }; |
448 | |
449 | template<class R, class Arg1, class Arg2> |
450 | struct bind_traits<R(Arg1, Arg2)> { |
451 | typedef R(&type)(Arg1, Arg2); |
452 | }; |
453 | |
454 | template<class R, class Arg1, class Arg2, class Arg3> |
455 | struct bind_traits<R(Arg1, Arg2, Arg3)> { |
456 | typedef R(&type)(Arg1, Arg2, Arg3); |
457 | }; |
458 | |
459 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4> |
460 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4)> { |
461 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4); |
462 | }; |
463 | |
464 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> |
465 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4, Arg5)> { |
466 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5); |
467 | }; |
468 | |
469 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> |
470 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> { |
471 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); |
472 | }; |
473 | |
474 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7> |
475 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> { |
476 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); |
477 | }; |
478 | |
479 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8> |
480 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> { |
481 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8); |
482 | }; |
483 | |
484 | template<class R, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Arg9> |
485 | struct bind_traits<R(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9)> { |
486 | typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9); |
487 | }; |
488 | |
489 | template<class T> |
490 | struct bind_traits<reference_wrapper<T> >{ |
491 | typedef T& type; |
492 | }; |
493 | |
494 | template<class T> |
495 | struct bind_traits<const reference_wrapper<T> >{ |
496 | typedef T& type; |
497 | }; |
498 | |
499 | template<> |
500 | struct bind_traits<void> { |
501 | typedef void type; |
502 | }; |
503 | |
504 | |
505 | |
506 | template < |
507 | class T0 = null_type, class T1 = null_type, class T2 = null_type, |
508 | class T3 = null_type, class T4 = null_type, class T5 = null_type, |
509 | class T6 = null_type, class T7 = null_type, class T8 = null_type, |
510 | class T9 = null_type |
511 | > |
512 | struct bind_tuple_mapper { |
513 | typedef |
514 | tuple<typename bind_traits<T0>::type, |
515 | typename bind_traits<T1>::type, |
516 | typename bind_traits<T2>::type, |
517 | typename bind_traits<T3>::type, |
518 | typename bind_traits<T4>::type, |
519 | typename bind_traits<T5>::type, |
520 | typename bind_traits<T6>::type, |
521 | typename bind_traits<T7>::type, |
522 | typename bind_traits<T8>::type, |
523 | typename bind_traits<T9>::type> type; |
524 | }; |
525 | |
526 | // bind_traits, except map const T& -> const T |
527 | // this is needed e.g. in currying. Const reference arguments can |
528 | // refer to temporaries, so it is not safe to store them as references. |
529 | template <class T> struct remove_const_reference { |
530 | typedef typename bind_traits<T>::type type; |
531 | }; |
532 | |
533 | template <class T> struct remove_const_reference<const T&> { |
534 | typedef const T type; |
535 | }; |
536 | |
537 | |
538 | // maps the bind argument types to the resulting lambda functor type |
539 | template < |
540 | class T0 = null_type, class T1 = null_type, class T2 = null_type, |
541 | class T3 = null_type, class T4 = null_type, class T5 = null_type, |
542 | class T6 = null_type, class T7 = null_type, class T8 = null_type, |
543 | class T9 = null_type |
544 | > |
545 | class bind_type_generator { |
546 | |
547 | typedef typename |
548 | detail::bind_tuple_mapper< |
549 | T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 |
550 | >::type args_t; |
551 | |
552 | BOOST_STATIC_CONSTANT(int, nof_elems = boost::tuples::length<args_t>::value); |
553 | |
554 | typedef |
555 | action< |
556 | nof_elems, |
557 | function_action<nof_elems> |
558 | > action_type; |
559 | |
560 | public: |
561 | typedef |
562 | lambda_functor< |
563 | lambda_functor_base< |
564 | action_type, |
565 | args_t |
566 | > |
567 | > type; |
568 | |
569 | }; |
570 | |
571 | |
572 | |
573 | } // detail |
574 | |
575 | template <class T> inline const T& make_const(const T& t) { return t; } |
576 | |
577 | |
578 | } // end of namespace lambda |
579 | } // end of namespace boost |
580 | |
581 | |
582 | |
583 | #endif // BOOST_LAMBDA_TRAITS_HPP |
584 | |