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