Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / lambda / detail / operator_return_type_traits.hpp
1 //  operator_return_type_traits.hpp -- Boost Lambda Library ------------------
2
3 // Copyright (C) 1999, 2000 Jaakko J√§rvi (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 #ifndef BOOST_LAMBDA_OPERATOR_RETURN_TYPE_TRAITS_HPP
12 #define BOOST_LAMBDA_OPERATOR_RETURN_TYPE_TRAITS_HPP
13
14 #include "boost/lambda/detail/is_instance_of.hpp"
15 #include "boost/type_traits/same_traits.hpp"
16
17 #include "boost/indirect_reference.hpp"
18
19 #include <cstddef> // needed for the ptrdiff_t
20 #include <iosfwd>  // for istream and ostream
21
22 #include <iterator> // needed for operator&
23
24 namespace boost { 
25 namespace lambda {
26 namespace detail {
27
28 // -- general helper templates for type deduction ------------------
29
30 // Much of the type deduction code for standard arithmetic types from Gary Powell
31
32 template <class A> struct promote_code { static const int value = -1; };
33 // this means that a code is not defined for A
34
35 // -- the next 5 types are needed in if_then_else_return 
36 // the promotion order is not important, but they must have distinct values.
37 template <> struct promote_code<bool> { static const int value = 10; };
38 template <> struct promote_code<char> { static const int value = 20; };
39 template <> struct promote_code<unsigned char> { static const int value = 30; };
40 template <> struct promote_code<signed char> { static const int value = 40; };
41 template <> struct promote_code<short int> { static const int value = 50; };
42 // ----------
43
44 template <> struct promote_code<int> { static const int value = 100; };
45 template <> struct promote_code<unsigned int> { static const int value = 200; };
46 template <> struct promote_code<long> { static const int value = 300; };
47 template <> struct promote_code<unsigned long> { static const int value = 400; };
48
49 template <> struct promote_code<float> { static const int value = 500; };
50 template <> struct promote_code<double> { static const int value = 600; };
51 template <> struct promote_code<long double> { static const int value = 700; };
52
53 // TODO: wchar_t
54
55 // forward delcaration of complex.
56
57 } // namespace detail
58 } // namespace lambda 
59 } // namespace boost
60
61 namespace std {
62   template<class T> class complex;
63 }
64
65 namespace boost { 
66 namespace lambda {
67 namespace detail {
68
69 template <> struct promote_code< std::complex<float> > { static const int value = 800; };
70 template <> struct promote_code< std::complex<double> > { static const int value = 900; };
71 template <> struct promote_code< std::complex<long double> > { static const int value = 1000; };
72
73 // -- int promotion -------------------------------------------
74 template <class T> struct promote_to_int { typedef T type; };
75
76 template <> struct promote_to_int<bool> { typedef int type; };
77 template <> struct promote_to_int<char> { typedef int type; };
78 template <> struct promote_to_int<unsigned char> { typedef int type; };
79 template <> struct promote_to_int<signed char> { typedef int type; };
80 template <> struct promote_to_int<short int> { typedef int type; };
81
82 // The unsigned short int promotion rule is this:
83 // unsigned short int to signed int if a signed int can hold all values 
84 // of unsigned short int, otherwise go to unsigned int.
85 template <> struct promote_to_int<unsigned short int>
86
87         typedef
88                 detail::IF<sizeof(int) <= sizeof(unsigned short int),        
89 // I had the logic reversed but ">" messes up the parsing.
90                 unsigned int,
91                 int>::RET type; 
92 };
93
94
95 // TODO: think, should there be default behaviour for non-standard types?
96
97 } // namespace detail
98
99 // ------------------------------------------ 
100 // Unary actions ----------------------------
101 // ------------------------------------------ 
102
103 template<class Act, class A>
104 struct plain_return_type_1 {
105   typedef detail::unspecified type;
106 };
107
108
109
110 template<class Act, class A>
111 struct plain_return_type_1<unary_arithmetic_action<Act>, A> {
112   typedef A type;
113 };
114
115 template<class Act, class A> 
116 struct return_type_1<unary_arithmetic_action<Act>, A> { 
117   typedef 
118     typename plain_return_type_1<
119       unary_arithmetic_action<Act>,
120       typename detail::remove_reference_and_cv<A>::type
121     >::type type;
122 };
123
124
125 template<class A>
126 struct plain_return_type_1<bitwise_action<not_action>, A> {
127   typedef A type;
128 };
129
130 // bitwise not, operator~()
131 template<class A> struct return_type_1<bitwise_action<not_action>, A> {
132   typedef 
133     typename plain_return_type_1<
134       bitwise_action<not_action>,
135       typename detail::remove_reference_and_cv<A>::type
136     >::type type;
137 };
138
139
140 // prefix increment and decrement operators return 
141 // their argument by default as a non-const reference
142 template<class Act, class A> 
143 struct plain_return_type_1<pre_increment_decrement_action<Act>, A> {
144   typedef A& type;
145 };
146
147 template<class Act, class A> 
148 struct return_type_1<pre_increment_decrement_action<Act>, A> {
149   typedef 
150     typename plain_return_type_1<
151       pre_increment_decrement_action<Act>,
152       typename detail::remove_reference_and_cv<A>::type
153     >::type type;
154 };
155
156 // post decrement just returns the same plain type.
157 template<class Act, class A>
158 struct plain_return_type_1<post_increment_decrement_action<Act>, A> {
159   typedef A type;
160 };
161
162 template<class Act, class A> 
163 struct return_type_1<post_increment_decrement_action<Act>, A> 
164
165   typedef 
166     typename plain_return_type_1<
167       post_increment_decrement_action<Act>,
168       typename detail::remove_reference_and_cv<A>::type
169     >::type type;
170 };
171
172 // logical not, operator!()
173 template<class A> 
174 struct plain_return_type_1<logical_action<not_action>, A> {
175   typedef bool type;
176 };
177
178 template<class A>
179 struct return_type_1<logical_action<not_action>, A> {
180   typedef 
181     typename plain_return_type_1<
182       logical_action<not_action>,
183       typename detail::remove_reference_and_cv<A>::type
184     >::type type;
185 };
186
187 // address of action ---------------------------------------
188
189
190 template<class A> 
191 struct return_type_1<other_action<addressof_action>, A> { 
192   typedef 
193     typename plain_return_type_1<
194       other_action<addressof_action>, 
195       typename detail::remove_reference_and_cv<A>::type
196     >::type type1;
197
198   // If no user defined specialization for A, then return the
199   // cv qualified pointer to A
200   typedef typename detail::IF<
201     boost::is_same<type1, detail::unspecified>::value, 
202     typename boost::remove_reference<A>::type*,
203     type1
204   >::RET type;
205 };
206
207 // contentsof action ------------------------------------
208
209 // TODO: this deduction may lead to fail directly, 
210 // (if A has no specialization for iterator_traits and has no
211 // typedef A::reference.
212 // There is no easy way around this, cause there doesn't seem to be a way
213 // to test whether a class is an iterator or not.
214  
215 // The default works with std::iterators.
216
217 namespace detail {
218
219   // A is a nonreference type
220 template <class A> struct contentsof_type {
221   typedef typename boost::indirect_reference<A>::type type; 
222 };
223
224   // this is since the nullary () in lambda_functor is always instantiated
225 template <> struct contentsof_type<null_type> {
226   typedef detail::unspecified type;
227 };
228
229
230 template <class A> struct contentsof_type<const A> {
231   typedef typename contentsof_type<A>::type type1;
232   // return a reference to the underlying const type
233   // the IF is because the A::reference in the primary template could
234   // be some class type rather than a real reference, hence
235   // we do not want to make it a reference here either
236     typedef typename detail::IF<
237       is_reference<type1>::value, 
238       const typename boost::remove_reference<type1>::type &,
239       const type1
240   >::RET type;
241 };
242
243 template <class A> struct contentsof_type<volatile A> {
244   typedef typename contentsof_type<A>::type type1;
245   typedef typename detail::IF<
246     is_reference<type1>::value, 
247     volatile typename boost::remove_reference<type1>::type &,
248     volatile type1
249   >::RET type;
250 };
251
252 template <class A> struct contentsof_type<const volatile A> {
253   typedef typename contentsof_type<A>::type type1;
254   typedef typename detail::IF<
255     is_reference<type1>::value, 
256     const volatile typename boost::remove_reference<type1>::type &,
257     const volatile type1
258   >::RET type;
259 };
260
261   // standard iterator traits should take care of the pointer types 
262   // but just to be on the safe side, we have the specializations here:
263   // these work even if A is cv-qualified.
264 template <class A> struct contentsof_type<A*> {
265   typedef A& type;
266 };
267 template <class A> struct contentsof_type<A* const> {
268   typedef A& type;
269 };
270 template <class A> struct contentsof_type<A* volatile> {
271   typedef A& type;
272 };
273 template <class A> struct contentsof_type<A* const volatile> {
274   typedef A& type;
275 };
276
277 template<class A, int N> struct contentsof_type<A[N]> { 
278   typedef A& type; 
279 };
280 template<class A, int N> struct contentsof_type<const A[N]> { 
281   typedef const A& type; 
282 };
283 template<class A, int N> struct contentsof_type<volatile A[N]> { 
284   typedef volatile A& type; 
285 };
286 template<class A, int N> struct contentsof_type<const volatile A[N]> { 
287   typedef const volatile A& type; 
288 };
289
290
291
292
293
294 } // end detail
295
296 template<class A> 
297 struct return_type_1<other_action<contentsof_action>, A> { 
298
299   typedef 
300     typename plain_return_type_1<
301       other_action<contentsof_action>, 
302       typename detail::remove_reference_and_cv<A>::type
303     >::type type1;
304
305   // If no user defined specialization for A, then return the
306   // cv qualified pointer to A
307   typedef typename 
308   detail::IF_type<
309     boost::is_same<type1, detail::unspecified>::value, 
310     detail::contentsof_type<
311       typename boost::remove_reference<A>::type
312     >,
313     detail::identity_mapping<type1>
314   >::type type;
315 };
316
317
318 // ------------------------------------------------------------------
319 // binary actions ---------------------------------------------------
320 // ------------------------------------------------------------------
321
322 // here the default case is: no user defined versions:
323 template <class Act, class A, class B>
324 struct plain_return_type_2 {
325   typedef detail::unspecified type; 
326 };
327
328 namespace detail {
329
330 // error classes
331 class illegal_pointer_arithmetic{};
332
333 // pointer arithmetic type deductions ----------------------
334 // value = false means that this is not a pointer arithmetic case
335 // value = true means, that this can be a pointer arithmetic case, but not necessarily is
336 // This means, that for user defined operators for pointer types, say for some operator+(X, *Y),
337 // the deductions must be coded at an earliel level (return_type_2).
338
339 template<class Act, class A, class B> 
340 struct pointer_arithmetic_traits { static const bool value = false; };
341
342 template<class A, class B> 
343 struct pointer_arithmetic_traits<plus_action, A, B> { 
344
345   typedef typename 
346     array_to_pointer<typename boost::remove_reference<A>::type>::type AP;
347   typedef typename 
348     array_to_pointer<typename boost::remove_reference<B>::type>::type BP;
349
350   static const bool is_pointer_A = boost::is_pointer<AP>::value;
351   static const bool is_pointer_B = boost::is_pointer<BP>::value;  
352
353   static const bool value = is_pointer_A || is_pointer_B;
354
355   // can't add two pointers.
356   // note, that we do not check wether the other type is valid for 
357   // addition with a pointer.
358   // the compiler will catch it in the apply function
359
360   typedef typename 
361   detail::IF<
362     is_pointer_A && is_pointer_B, 
363       detail::return_type_deduction_failure<
364         detail::illegal_pointer_arithmetic
365       >,
366       typename detail::IF<is_pointer_A, AP, BP>::RET
367   >::RET type; 
368
369 };
370
371 template<class A, class B> 
372 struct pointer_arithmetic_traits<minus_action, A, B> { 
373   typedef typename 
374     array_to_pointer<typename boost::remove_reference<A>::type>::type AP;
375   typedef typename 
376     array_to_pointer<typename boost::remove_reference<B>::type>::type BP;
377
378   static const bool is_pointer_A = boost::is_pointer<AP>::value;
379   static const bool is_pointer_B = boost::is_pointer<BP>::value;  
380
381   static const bool value = is_pointer_A || is_pointer_B;
382
383   static const bool same_pointer_type =
384     is_pointer_A && is_pointer_B && 
385     boost::is_same<
386       typename boost::remove_const<
387         typename boost::remove_pointer<
388           typename boost::remove_const<AP>::type
389         >::type
390       >::type,
391       typename boost::remove_const<
392         typename boost::remove_pointer<
393           typename boost::remove_const<BP>::type
394         >::type
395       >::type
396     >::value;
397
398   // ptr - ptr has type ptrdiff_t
399   // note, that we do not check if, in ptr - B, B is 
400   // valid for subtraction with a pointer.
401   // the compiler will catch it in the apply function
402
403   typedef typename 
404   detail::IF<
405     same_pointer_type, const std::ptrdiff_t,
406     typename detail::IF<
407       is_pointer_A, 
408       AP, 
409       detail::return_type_deduction_failure<detail::illegal_pointer_arithmetic>
410     >::RET
411   >::RET type; 
412 };
413
414 } // namespace detail
415    
416 // -- arithmetic actions ---------------------------------------------
417
418 namespace detail {
419    
420 template<bool is_pointer_arithmetic, class Act, class A, class B> 
421 struct return_type_2_arithmetic_phase_1;
422
423 template<class A, class B> struct return_type_2_arithmetic_phase_2;
424 template<class A, class B> struct return_type_2_arithmetic_phase_3;
425
426 } // namespace detail
427   
428
429 // drop any qualifiers from the argument types within arithmetic_action
430 template<class A, class B, class Act> 
431 struct return_type_2<arithmetic_action<Act>, A, B>
432 {
433   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
434   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
435
436   typedef typename 
437     plain_return_type_2<arithmetic_action<Act>, plain_A, plain_B>::type type1;
438   
439   // if user defined return type, do not enter the whole arithmetic deductions
440   typedef typename 
441     detail::IF_type<
442       boost::is_same<type1, detail::unspecified>::value, 
443       detail::return_type_2_arithmetic_phase_1<
444          detail::pointer_arithmetic_traits<Act, A, B>::value, Act, A, B
445       >,
446       plain_return_type_2<arithmetic_action<Act>, plain_A, plain_B>
447     >::type type;
448 };
449
450 namespace detail {
451    
452 // perform integral promotion, no pointer arithmetic
453 template<bool is_pointer_arithmetic, class Act, class A, class B> 
454 struct return_type_2_arithmetic_phase_1
455 {
456   typedef typename 
457     return_type_2_arithmetic_phase_2<
458       typename remove_reference_and_cv<A>::type,
459       typename remove_reference_and_cv<B>::type
460     >::type type;
461 };
462
463 // pointer_arithmetic
464 template<class Act, class A, class B> 
465 struct return_type_2_arithmetic_phase_1<true, Act, A, B>
466 {
467   typedef typename 
468     pointer_arithmetic_traits<Act, A, B>::type type;
469 };
470
471 template<class A, class B>
472 struct return_type_2_arithmetic_phase_2 {
473   typedef typename
474     return_type_2_arithmetic_phase_3<
475       typename promote_to_int<A>::type, 
476       typename promote_to_int<B>::type
477     >::type type;
478 };
479
480 // specialization for unsigned int.
481 // We only have to do these two specialization because the value promotion will
482 // take care of the other cases.
483 // The unsigned int promotion rule is this:
484 // unsigned int to long if a long can hold all values of unsigned int,
485 // otherwise go to unsigned long.
486
487 // struct so I don't have to type this twice.
488 struct promotion_of_unsigned_int
489 {
490         typedef
491         detail::IF<sizeof(long) <= sizeof(unsigned int),        
492                 unsigned long,
493                 long>::RET type; 
494 };
495
496 template<>
497 struct return_type_2_arithmetic_phase_2<unsigned int, long>
498 {
499         typedef promotion_of_unsigned_int::type type;
500 };
501 template<>
502 struct return_type_2_arithmetic_phase_2<long, unsigned int>
503 {
504         typedef promotion_of_unsigned_int::type type;
505 };
506
507
508 template<class A, class B> struct return_type_2_arithmetic_phase_3 { 
509    enum { promote_code_A_value = promote_code<A>::value,
510          promote_code_B_value = promote_code<B>::value }; // enums for KCC
511   typedef typename
512     detail::IF<
513       promote_code_A_value == -1 || promote_code_B_value == -1,
514       detail::return_type_deduction_failure<return_type_2_arithmetic_phase_3>,
515       typename detail::IF<
516         ((int)promote_code_A_value > (int)promote_code_B_value), 
517         A, 
518         B
519       >::RET
520     >::RET type;                    
521 };
522
523 } // namespace detail
524
525 // --  bitwise actions -------------------------------------------
526 // note: for integral types deuduction is similar to arithmetic actions. 
527
528 // drop any qualifiers from the argument types within arithmetic action
529 template<class A, class B, class Act> 
530 struct return_type_2<bitwise_action<Act>, A, B>
531 {
532
533   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
534   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
535
536   typedef typename 
537     plain_return_type_2<bitwise_action<Act>, plain_A, plain_B>::type type1;
538   
539   // if user defined return type, do not enter type deductions
540   typedef typename 
541     detail::IF_type<
542       boost::is_same<type1, detail::unspecified>::value, 
543       return_type_2<arithmetic_action<plus_action>, A, B>,
544       plain_return_type_2<bitwise_action<Act>, plain_A, plain_B>
545     >::type type;
546
547   // plus_action is just a random pick, has to be a concrete instance
548
549   // TODO: This check is only valid for built-in types, overloaded types might
550   // accept floating point operators
551
552   // bitwise operators not defined for floating point types
553   // these test are not strictly needed here, since the error will be caught in
554   // the apply function
555   BOOST_STATIC_ASSERT(!(boost::is_float<plain_A>::value && boost::is_float<plain_B>::value));
556
557 };
558
559 namespace detail {
560
561 #ifdef BOOST_NO_TEMPLATED_STREAMS
562
563 template<class A, class B>
564 struct leftshift_type {
565
566   typedef typename detail::IF<
567     boost::is_convertible<
568       typename boost::remove_reference<A>::type*,
569       std::ostream*
570     >::value,
571     std::ostream&, 
572     typename detail::remove_reference_and_cv<A>::type
573   >::RET type;
574 };
575
576 template<class A, class B>
577 struct rightshift_type {
578
579   typedef typename detail::IF<
580
581     boost::is_convertible<
582       typename boost::remove_reference<A>::type*,
583       std::istream*
584     >::value, 
585     std::istream&,
586     typename detail::remove_reference_and_cv<A>::type
587   >::RET type;
588 };
589
590 #else
591
592 template <class T> struct get_ostream_type {
593   typedef std::basic_ostream<typename T::char_type, 
594                              typename T::traits_type>& type;
595 };
596
597 template <class T> struct get_istream_type {
598   typedef std::basic_istream<typename T::char_type, 
599                              typename T::traits_type>& type;
600 };
601
602 template<class A, class B>
603 struct leftshift_type {
604 private:
605   typedef typename boost::remove_reference<A>::type plainA;
606 public:
607   typedef typename detail::IF_type<
608     is_instance_of_2<plainA, std::basic_ostream>::value, 
609     get_ostream_type<plainA>, //reference to the stream 
610     detail::remove_reference_and_cv<A>
611   >::type type;
612 };
613
614 template<class A, class B>
615 struct rightshift_type {
616 private:
617   typedef typename boost::remove_reference<A>::type plainA;
618 public:
619   typedef typename detail::IF_type<
620     is_instance_of_2<plainA, std::basic_istream>::value, 
621     get_istream_type<plainA>, //reference to the stream 
622     detail::remove_reference_and_cv<A>
623   >::type type;
624 };
625
626
627 #endif
628
629 } // end detail
630
631 // ostream
632 template<class A, class B> 
633 struct return_type_2<bitwise_action<leftshift_action>, A, B>
634 {
635   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
636   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
637
638   typedef typename 
639     plain_return_type_2<bitwise_action<leftshift_action>, plain_A, plain_B>::type type1;
640   
641   // if user defined return type, do not enter type deductions
642   typedef typename 
643     detail::IF_type<
644       boost::is_same<type1, detail::unspecified>::value, 
645       detail::leftshift_type<A, B>,
646       plain_return_type_2<bitwise_action<leftshift_action>, plain_A, plain_B>
647     >::type type;
648 };
649
650 // istream
651 template<class A, class B> 
652 struct return_type_2<bitwise_action<rightshift_action>, A, B>
653 {
654   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
655   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
656
657   typedef typename 
658     plain_return_type_2<bitwise_action<rightshift_action>, plain_A, plain_B>::type type1;
659   
660   // if user defined return type, do not enter type deductions
661   typedef typename 
662     detail::IF_type<
663       boost::is_same<type1, detail::unspecified>::value, 
664       detail::rightshift_type<A, B>,
665       plain_return_type_2<bitwise_action<rightshift_action>, plain_A, plain_B>
666     >::type type;
667 };
668
669 // -- logical actions ----------------------------------------
670 // always bool
671 // NOTE: this may not be true for some weird user-defined types,
672 template<class A, class B, class Act> 
673 struct plain_return_type_2<logical_action<Act>, A, B> { 
674   typedef bool type; 
675 };
676
677 template<class A, class B, class Act> 
678 struct return_type_2<logical_action<Act>, A, B> { 
679
680   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
681   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
682
683   typedef typename 
684     plain_return_type_2<logical_action<Act>, plain_A, plain_B>::type type;
685   
686 };
687
688
689 // -- relational actions ----------------------------------------
690 // always bool
691 // NOTE: this may not be true for some weird user-defined types,
692 template<class A, class B, class Act> 
693 struct plain_return_type_2<relational_action<Act>, A, B> { 
694   typedef bool type; 
695 };
696
697 template<class A, class B, class Act> 
698 struct return_type_2<relational_action<Act>, A, B> { 
699
700   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
701   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
702
703   typedef typename 
704     plain_return_type_2<relational_action<Act>, plain_A, plain_B>::type type; 
705 };
706
707 // Assingment actions -----------------------------------------------
708 // return type is the type of the first argument as reference
709
710 // note that cv-qualifiers are preserved.
711 // Yes, assignment operator can be const!
712
713 // NOTE: this may not be true for some weird user-defined types,
714
715 template<class A, class B, class Act> 
716 struct return_type_2<arithmetic_assignment_action<Act>, A, B> { 
717
718   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
719   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
720
721   typedef typename 
722     plain_return_type_2<
723       arithmetic_assignment_action<Act>, plain_A, plain_B
724     >::type type1;
725   
726   typedef typename 
727     detail::IF<
728       boost::is_same<type1, detail::unspecified>::value, 
729       typename boost::add_reference<A>::type,
730       type1
731     >::RET type;
732 };
733
734 template<class A, class B, class Act> 
735 struct return_type_2<bitwise_assignment_action<Act>, A, B> { 
736
737   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
738   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
739
740   typedef typename 
741     plain_return_type_2<
742       bitwise_assignment_action<Act>, plain_A, plain_B
743     >::type type1;
744   
745   typedef typename 
746     detail::IF<
747       boost::is_same<type1, detail::unspecified>::value, 
748       typename boost::add_reference<A>::type,
749       type1
750     >::RET type;
751 };
752
753 template<class A, class B> 
754 struct return_type_2<other_action<assignment_action>, A, B> { 
755   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
756   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
757
758   typedef typename 
759     plain_return_type_2<
760       other_action<assignment_action>, plain_A, plain_B
761     >::type type1;
762   
763   typedef typename 
764     detail::IF<
765       boost::is_same<type1, detail::unspecified>::value, 
766       typename boost::add_reference<A>::type,
767       type1
768     >::RET type;
769 };
770
771 // -- other actions ----------------------------------------
772
773 // comma action ----------------------------------
774 // Note: this may not be true for some weird user-defined types,
775
776 // NOTE! This only tries the plain_return_type_2 layer and gives
777 // detail::unspecified as default. If no such specialization is found, the 
778 // type rule in the spcecialization of the return_type_2_prot is used
779 // to give the type of the right argument (which can be a reference too)
780 // (The built in operator, can return a l- or rvalue).
781 template<class A, class B> 
782 struct return_type_2<other_action<comma_action>, A, B> { 
783
784   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
785   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
786
787   typedef typename 
788     plain_return_type_2<
789       other_action<comma_action>, plain_A, plain_B
790     >::type type;
791   };
792
793 // subscript action -----------------------------------------------
794
795
796 namespace detail {
797   // A and B are nonreference types
798 template <class A, class B> struct subscript_type {
799   typedef detail::unspecified type; 
800 };
801
802 template <class A, class B> struct subscript_type<A*, B> {
803   typedef A& type;
804 };
805 template <class A, class B> struct subscript_type<A* const, B> {
806   typedef A& type;
807 };
808 template <class A, class B> struct subscript_type<A* volatile, B> {
809   typedef A& type;
810 };
811 template <class A, class B> struct subscript_type<A* const volatile, B> {
812   typedef A& type;
813 };
814
815
816 template<class A, class B, int N> struct subscript_type<A[N], B> { 
817   typedef A& type; 
818 };
819
820   // these 3 specializations are needed to make gcc <3 happy
821 template<class A, class B, int N> struct subscript_type<const A[N], B> { 
822   typedef const A& type; 
823 };
824 template<class A, class B, int N> struct subscript_type<volatile A[N], B> { 
825   typedef volatile A& type; 
826 };
827 template<class A, class B, int N> struct subscript_type<const volatile A[N], B> { 
828   typedef const volatile A& type; 
829 };
830
831 } // end detail
832
833 template<class A, class B>
834 struct return_type_2<other_action<subscript_action>, A, B> {
835
836   typedef typename detail::remove_reference_and_cv<A>::type plain_A;
837   typedef typename detail::remove_reference_and_cv<B>::type plain_B;
838
839   typedef typename boost::remove_reference<A>::type nonref_A;
840   typedef typename boost::remove_reference<B>::type nonref_B;
841
842   typedef typename 
843     plain_return_type_2<
844       other_action<subscript_action>, plain_A, plain_B
845     >::type type1;
846   
847   typedef typename 
848     detail::IF_type<
849       boost::is_same<type1, detail::unspecified>::value, 
850       detail::subscript_type<nonref_A, nonref_B>,
851       plain_return_type_2<other_action<subscript_action>, plain_A, plain_B>
852     >::type type;
853
854 };
855
856
857 } // namespace lambda
858 } // namespace boost
859
860
861 // Forward declarations are incompatible with the libstdc++ debug mode.
862 #if BOOST_WORKAROUND(__GNUC__, >= 3) && _GLIBCXX_DEBUG
863 #include <string>
864 #include <vector>
865 #include <map>
866 #include <deque>
867 #else
868
869 // The GCC 2.95.x uses a non-conformant deque
870 #if BOOST_WORKAROUND(__GNUC__, == 2) && __GNUC_MINOR__ <= 96
871 #include <deque>
872 #else
873
874 namespace std {
875   template <class T, class Allocator> class deque;
876 }
877
878 #endif
879
880 namespace std {
881  template <class Char, class Traits, class Allocator> class basic_string;
882  template <class T, class Allocator> class vector;
883  template <class Key, class T, class Cmp, class Allocator> class map;
884  template <class Key, class T, class Cmp, class Allocator> class multimap;
885 }
886
887 #endif
888
889
890
891 namespace boost { 
892 namespace lambda {
893
894 template<class Key, class T, class Cmp, class Allocator, class B> 
895 struct plain_return_type_2<other_action<subscript_action>, std::map<Key, T, Cmp, Allocator>, B> { 
896   typedef T& type;
897   // T == std::map<Key, T, Cmp, Allocator>::mapped_type; 
898 };
899
900 template<class Key, class T, class Cmp, class Allocator, class B> 
901 struct plain_return_type_2<other_action<subscript_action>, std::multimap<Key, T, Cmp, Allocator>, B> { 
902   typedef T& type;
903   // T == std::map<Key, T, Cmp, Allocator>::mapped_type; 
904 };
905
906   // deque
907 template<class T, class Allocator, class B> 
908 struct plain_return_type_2<other_action<subscript_action>, std::deque<T, Allocator>, B> { 
909   typedef typename std::deque<T, Allocator>::reference type;
910 };
911 template<class T, class Allocator, class B> 
912 struct plain_return_type_2<other_action<subscript_action>, const std::deque<T, Allocator>, B> { 
913   typedef typename std::deque<T, Allocator>::const_reference type;
914 };
915
916   // vector
917 template<class T, class Allocator, class B> 
918 struct plain_return_type_2<other_action<subscript_action>, std::vector<T, Allocator>, B> { 
919   typedef typename std::vector<T, Allocator>::reference type;
920 };
921 template<class T, class Allocator, class B> 
922 struct plain_return_type_2<other_action<subscript_action>, const std::vector<T, Allocator>, B> { 
923   typedef typename std::vector<T, Allocator>::const_reference type;
924 };
925
926   // basic_string
927 template<class Char, class Traits, class Allocator, class B> 
928 struct plain_return_type_2<other_action<subscript_action>, std::basic_string<Char, Traits, Allocator>, B> { 
929   typedef typename std::basic_string<Char, Traits, Allocator>::reference type;
930 };
931 template<class Char, class Traits, class Allocator, class B> 
932 struct plain_return_type_2<other_action<subscript_action>, const std::basic_string<Char, Traits, Allocator>, B> { 
933   typedef typename std::basic_string<Char, Traits, Allocator>::const_reference type;
934 };
935
936
937 } // namespace lambda
938 } // namespace boost
939
940 #endif
941
942