1// extending_return_type_traits.cpp -- The Boost Lambda Library --------
2//
3// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
4// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com)
5//
6// Distributed under the Boost Software License, Version 1.0. (See
7// accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9//
10// For more information, see www.boost.org
11
12// -----------------------------------------------------------------------
13
14
15#include <boost/core/lightweight_test.hpp>
16#define BOOST_CHECK BOOST_TEST
17
18#include "boost/lambda/bind.hpp"
19#include "boost/lambda/lambda.hpp"
20#include "boost/lambda/detail/suppress_unused.hpp"
21
22#include <iostream>
23
24#include <functional>
25
26#include <algorithm>
27
28using boost::lambda::detail::suppress_unused_variable_warnings;
29
30class A {};
31class B {};
32
33using namespace boost::lambda;
34
35
36B operator--(const A&, int) { return B(); }
37B operator--(A&) { return B(); }
38B operator++(const A&, int) { return B(); }
39B operator++(A&) { return B(); }
40B operator-(const A&) { return B(); }
41B operator+(const A&) { return B(); }
42
43B operator!(const A&) { return B(); }
44
45B operator&(const A&) { return B(); }
46B operator*(const A&) { return B(); }
47
48namespace boost {
49namespace lambda {
50
51 // unary + and -
52template<class Act>
53struct plain_return_type_1<unary_arithmetic_action<Act>, A > {
54 typedef B type;
55};
56
57 // post incr/decr
58template<class Act>
59struct plain_return_type_1<post_increment_decrement_action<Act>, A > {
60 typedef B type;
61};
62
63 // pre incr/decr
64template<class Act>
65struct plain_return_type_1<pre_increment_decrement_action<Act>, A > {
66 typedef B type;
67};
68 // !
69template<>
70struct plain_return_type_1<logical_action<not_action>, A> {
71 typedef B type;
72};
73 // &
74template<>
75struct plain_return_type_1<other_action<addressof_action>, A> {
76 typedef B type;
77};
78 // *
79template<>
80struct plain_return_type_1<other_action<contentsof_action>, A> {
81 typedef B type;
82};
83
84
85} // lambda
86} // boost
87
88void ok(B /*b*/) {}
89
90void test_unary_operators()
91{
92 A a; int i = 1;
93 ok((++_1)(a));
94 ok((--_1)(a));
95 ok((_1++)(a));
96 ok((_1--)(a));
97 ok((+_1)(a));
98 ok((-_1)(a));
99 ok((!_1)(a));
100 ok((&_1)(a));
101 ok((*_1)(a));
102
103 BOOST_CHECK((*_1)(make_const(&i)) == 1);
104}
105
106class X {};
107class Y {};
108class Z {};
109
110Z operator+(const X&, const Y&) { return Z(); }
111Z operator-(const X&, const Y&) { return Z(); }
112X operator*(const X&, const Y&) { return X(); }
113
114Z operator/(const X&, const Y&) { return Z(); }
115Z operator%(const X&, const Y&) { return Z(); }
116
117class XX {};
118class YY {};
119class ZZ {};
120class VV {};
121
122// it is possible to support differently cv-qualified versions
123YY operator*(XX&, YY&) { return YY(); }
124ZZ operator*(const XX&, const YY&) { return ZZ(); }
125XX operator*(volatile XX&, volatile YY&) { return XX(); }
126VV operator*(const volatile XX&, const volatile YY&) { return VV(); }
127
128// the traits can be more complex:
129template <class T>
130class my_vector {};
131
132template<class A, class B>
133my_vector<typename return_type_2<arithmetic_action<plus_action>, A&, B&>::type>
134operator+(const my_vector<A>& /*a*/, const my_vector<B>& /*b*/)
135{
136 typedef typename
137 return_type_2<arithmetic_action<plus_action>, A&, B&>::type res_type;
138 return my_vector<res_type>();
139}
140
141
142
143// bitwise ops:
144X operator<<(const X&, const Y&) { return X(); }
145Z operator>>(const X&, const Y&) { return Z(); }
146Z operator&(const X&, const Y&) { return Z(); }
147Z operator|(const X&, const Y&) { return Z(); }
148Z operator^(const X&, const Y&) { return Z(); }
149
150// comparison ops:
151
152X operator<(const X&, const Y&) { return X(); }
153Z operator>(const X&, const Y&) { return Z(); }
154Z operator<=(const X&, const Y&) { return Z(); }
155Z operator>=(const X&, const Y&) { return Z(); }
156Z operator==(const X&, const Y&) { return Z(); }
157Z operator!=(const X&, const Y&) { return Z(); }
158
159// logical
160
161X operator&&(const X&, const Y&) { return X(); }
162Z operator||(const X&, const Y&) { return Z(); }
163
164// arithh assignment
165
166Z operator+=( X&, const Y&) { return Z(); }
167Z operator-=( X&, const Y&) { return Z(); }
168Y operator*=( X&, const Y&) { return Y(); }
169Z operator/=( X&, const Y&) { return Z(); }
170Z operator%=( X&, const Y&) { return Z(); }
171
172// bitwise assignment
173Z operator<<=( X&, const Y&) { return Z(); }
174Z operator>>=( X&, const Y&) { return Z(); }
175Y operator&=( X&, const Y&) { return Y(); }
176Z operator|=( X&, const Y&) { return Z(); }
177Z operator^=( X&, const Y&) { return Z(); }
178
179// assignment
180class Assign {
181public:
182 void operator=(const Assign& /*a*/) {}
183 X operator[](const int& /*i*/) { return X(); }
184};
185
186
187
188namespace boost {
189namespace lambda {
190
191 // you can do action groups
192template<class Act>
193struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
194 typedef Z type;
195};
196
197 // or specialize the exact action
198template<>
199struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
200 typedef X type;
201};
202
203 // if you want to make a distinction between differently cv-qualified
204 // types, you need to specialize on a different level:
205template<>
206struct return_type_2<arithmetic_action<multiply_action>, XX, YY> {
207 typedef YY type;
208};
209template<>
210struct return_type_2<arithmetic_action<multiply_action>, const XX, const YY> {
211 typedef ZZ type;
212};
213template<>
214struct return_type_2<arithmetic_action<multiply_action>, volatile XX, volatile YY> {
215 typedef XX type;
216};
217template<>
218struct return_type_2<arithmetic_action<multiply_action>, volatile const XX, const volatile YY> {
219 typedef VV type;
220};
221
222 // the mapping can be more complex:
223template<class A, class B>
224struct plain_return_type_2<arithmetic_action<plus_action>, my_vector<A>, my_vector<B> > {
225 typedef typename
226 return_type_2<arithmetic_action<plus_action>, A&, B&>::type res_type;
227 typedef my_vector<res_type> type;
228};
229
230 // bitwise binary:
231 // you can do action groups
232template<class Act>
233struct plain_return_type_2<bitwise_action<Act>, X, Y> {
234 typedef Z type;
235};
236
237 // or specialize the exact action
238template<>
239struct plain_return_type_2<bitwise_action<leftshift_action>, X, Y> {
240 typedef X type;
241};
242
243 // comparison binary:
244 // you can do action groups
245template<class Act>
246struct plain_return_type_2<relational_action<Act>, X, Y> {
247 typedef Z type;
248};
249
250 // or specialize the exact action
251template<>
252struct plain_return_type_2<relational_action<less_action>, X, Y> {
253 typedef X type;
254};
255
256 // logical binary:
257 // you can do action groups
258template<class Act>
259struct plain_return_type_2<logical_action<Act>, X, Y> {
260 typedef Z type;
261};
262
263 // or specialize the exact action
264template<>
265struct plain_return_type_2<logical_action<and_action>, X, Y> {
266 typedef X type;
267};
268
269 // arithmetic assignment :
270 // you can do action groups
271template<class Act>
272struct plain_return_type_2<arithmetic_assignment_action<Act>, X, Y> {
273 typedef Z type;
274};
275
276 // or specialize the exact action
277template<>
278struct plain_return_type_2<arithmetic_assignment_action<multiply_action>, X, Y> {
279 typedef Y type;
280};
281
282 // arithmetic assignment :
283 // you can do action groups
284template<class Act>
285struct plain_return_type_2<bitwise_assignment_action<Act>, X, Y> {
286 typedef Z type;
287};
288
289 // or specialize the exact action
290template<>
291struct plain_return_type_2<bitwise_assignment_action<and_action>, X, Y> {
292 typedef Y type;
293};
294
295 // assignment
296template<>
297struct plain_return_type_2<other_action<assignment_action>, Assign, Assign> {
298 typedef void type;
299};
300 // subscript
301template<>
302struct plain_return_type_2<other_action<subscript_action>, Assign, int> {
303 typedef X type;
304};
305
306
307} // end lambda
308} // end boost
309
310
311
312void test_binary_operators() {
313
314 X x; Y y;
315 (_1 + _2)(x, y);
316 (_1 - _2)(x, y);
317 (_1 * _2)(x, y);
318 (_1 / _2)(x, y);
319 (_1 % _2)(x, y);
320
321
322 // make a distinction between differently cv-qualified operators
323 XX xx; YY yy;
324 const XX& cxx = xx;
325 const YY& cyy = yy;
326 volatile XX& vxx = xx;
327 volatile YY& vyy = yy;
328 const volatile XX& cvxx = xx;
329 const volatile YY& cvyy = yy;
330
331 ZZ dummy1 = (_1 * _2)(cxx, cyy);
332 YY dummy2 = (_1 * _2)(xx, yy);
333 XX dummy3 = (_1 * _2)(vxx, vyy);
334 VV dummy4 = (_1 * _2)(cvxx, cvyy);
335
336 suppress_unused_variable_warnings(dummy1);
337 suppress_unused_variable_warnings(dummy2);
338 suppress_unused_variable_warnings(dummy3);
339 suppress_unused_variable_warnings(dummy4);
340
341 my_vector<int> v1; my_vector<double> v2;
342 my_vector<double> d = (_1 + _2)(v1, v2);
343
344 suppress_unused_variable_warnings(d);
345
346 // bitwise
347
348 (_1 << _2)(x, y);
349 (_1 >> _2)(x, y);
350 (_1 | _2)(x, y);
351 (_1 & _2)(x, y);
352 (_1 ^ _2)(x, y);
353
354 // comparison
355
356 (_1 < _2)(x, y);
357 (_1 > _2)(x, y);
358 (_1 <= _2)(x, y);
359 (_1 >= _2)(x, y);
360 (_1 == _2)(x, y);
361 (_1 != _2)(x, y);
362
363 // logical
364
365 (_1 || _2)(x, y);
366 (_1 && _2)(x, y);
367
368 // arithmetic assignment
369 (_1 += _2)(x, y);
370 (_1 -= _2)(x, y);
371 (_1 *= _2)(x, y);
372 (_1 /= _2)(x, y);
373 (_1 %= _2)(x, y);
374
375 // bitwise assignment
376 (_1 <<= _2)(x, y);
377 (_1 >>= _2)(x, y);
378 (_1 |= _2)(x, y);
379 (_1 &= _2)(x, y);
380 (_1 ^= _2)(x, y);
381
382}
383
384
385int main() {
386 test_unary_operators();
387 test_binary_operators();
388 return boost::report_errors();
389}
390

source code of boost/libs/lambda/test/extending_rt_traits.cpp