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 | |
28 | using boost::lambda::detail::suppress_unused_variable_warnings; |
29 | |
30 | class A {}; |
31 | class B {}; |
32 | |
33 | using namespace boost::lambda; |
34 | |
35 | |
36 | B operator--(const A&, int) { return B(); } |
37 | B operator--(A&) { return B(); } |
38 | B operator++(const A&, int) { return B(); } |
39 | B operator++(A&) { return B(); } |
40 | B operator-(const A&) { return B(); } |
41 | B operator+(const A&) { return B(); } |
42 | |
43 | B operator!(const A&) { return B(); } |
44 | |
45 | B operator&(const A&) { return B(); } |
46 | B operator*(const A&) { return B(); } |
47 | |
48 | namespace boost { |
49 | namespace lambda { |
50 | |
51 | // unary + and - |
52 | template<class Act> |
53 | struct plain_return_type_1<unary_arithmetic_action<Act>, A > { |
54 | typedef B type; |
55 | }; |
56 | |
57 | // post incr/decr |
58 | template<class Act> |
59 | struct plain_return_type_1<post_increment_decrement_action<Act>, A > { |
60 | typedef B type; |
61 | }; |
62 | |
63 | // pre incr/decr |
64 | template<class Act> |
65 | struct plain_return_type_1<pre_increment_decrement_action<Act>, A > { |
66 | typedef B type; |
67 | }; |
68 | // ! |
69 | template<> |
70 | struct plain_return_type_1<logical_action<not_action>, A> { |
71 | typedef B type; |
72 | }; |
73 | // & |
74 | template<> |
75 | struct plain_return_type_1<other_action<addressof_action>, A> { |
76 | typedef B type; |
77 | }; |
78 | // * |
79 | template<> |
80 | struct plain_return_type_1<other_action<contentsof_action>, A> { |
81 | typedef B type; |
82 | }; |
83 | |
84 | |
85 | } // lambda |
86 | } // boost |
87 | |
88 | void ok(B /*b*/) {} |
89 | |
90 | void 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 | |
106 | class X {}; |
107 | class Y {}; |
108 | class Z {}; |
109 | |
110 | Z operator+(const X&, const Y&) { return Z(); } |
111 | Z operator-(const X&, const Y&) { return Z(); } |
112 | X operator*(const X&, const Y&) { return X(); } |
113 | |
114 | Z operator/(const X&, const Y&) { return Z(); } |
115 | Z operator%(const X&, const Y&) { return Z(); } |
116 | |
117 | class XX {}; |
118 | class YY {}; |
119 | class ZZ {}; |
120 | class VV {}; |
121 | |
122 | // it is possible to support differently cv-qualified versions |
123 | YY operator*(XX&, YY&) { return YY(); } |
124 | ZZ operator*(const XX&, const YY&) { return ZZ(); } |
125 | XX operator*(volatile XX&, volatile YY&) { return XX(); } |
126 | VV operator*(const volatile XX&, const volatile YY&) { return VV(); } |
127 | |
128 | // the traits can be more complex: |
129 | template <class T> |
130 | class my_vector {}; |
131 | |
132 | template<class A, class B> |
133 | my_vector<typename return_type_2<arithmetic_action<plus_action>, A&, B&>::type> |
134 | operator+(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: |
144 | X operator<<(const X&, const Y&) { return X(); } |
145 | Z operator>>(const X&, const Y&) { return Z(); } |
146 | Z operator&(const X&, const Y&) { return Z(); } |
147 | Z operator|(const X&, const Y&) { return Z(); } |
148 | Z operator^(const X&, const Y&) { return Z(); } |
149 | |
150 | // comparison ops: |
151 | |
152 | X operator<(const X&, const Y&) { return X(); } |
153 | Z operator>(const X&, const Y&) { return Z(); } |
154 | Z operator<=(const X&, const Y&) { return Z(); } |
155 | Z operator>=(const X&, const Y&) { return Z(); } |
156 | Z operator==(const X&, const Y&) { return Z(); } |
157 | Z operator!=(const X&, const Y&) { return Z(); } |
158 | |
159 | // logical |
160 | |
161 | X operator&&(const X&, const Y&) { return X(); } |
162 | Z operator||(const X&, const Y&) { return Z(); } |
163 | |
164 | // arithh assignment |
165 | |
166 | Z operator+=( X&, const Y&) { return Z(); } |
167 | Z operator-=( X&, const Y&) { return Z(); } |
168 | Y operator*=( X&, const Y&) { return Y(); } |
169 | Z operator/=( X&, const Y&) { return Z(); } |
170 | Z operator%=( X&, const Y&) { return Z(); } |
171 | |
172 | // bitwise assignment |
173 | Z operator<<=( X&, const Y&) { return Z(); } |
174 | Z operator>>=( X&, const Y&) { return Z(); } |
175 | Y operator&=( X&, const Y&) { return Y(); } |
176 | Z operator|=( X&, const Y&) { return Z(); } |
177 | Z operator^=( X&, const Y&) { return Z(); } |
178 | |
179 | // assignment |
180 | class Assign { |
181 | public: |
182 | void operator=(const Assign& /*a*/) {} |
183 | X operator[](const int& /*i*/) { return X(); } |
184 | }; |
185 | |
186 | |
187 | |
188 | namespace boost { |
189 | namespace lambda { |
190 | |
191 | // you can do action groups |
192 | template<class Act> |
193 | struct plain_return_type_2<arithmetic_action<Act>, X, Y> { |
194 | typedef Z type; |
195 | }; |
196 | |
197 | // or specialize the exact action |
198 | template<> |
199 | struct 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: |
205 | template<> |
206 | struct return_type_2<arithmetic_action<multiply_action>, XX, YY> { |
207 | typedef YY type; |
208 | }; |
209 | template<> |
210 | struct return_type_2<arithmetic_action<multiply_action>, const XX, const YY> { |
211 | typedef ZZ type; |
212 | }; |
213 | template<> |
214 | struct return_type_2<arithmetic_action<multiply_action>, volatile XX, volatile YY> { |
215 | typedef XX type; |
216 | }; |
217 | template<> |
218 | struct 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: |
223 | template<class A, class B> |
224 | struct 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 |
232 | template<class Act> |
233 | struct plain_return_type_2<bitwise_action<Act>, X, Y> { |
234 | typedef Z type; |
235 | }; |
236 | |
237 | // or specialize the exact action |
238 | template<> |
239 | struct 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 |
245 | template<class Act> |
246 | struct plain_return_type_2<relational_action<Act>, X, Y> { |
247 | typedef Z type; |
248 | }; |
249 | |
250 | // or specialize the exact action |
251 | template<> |
252 | struct 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 |
258 | template<class Act> |
259 | struct plain_return_type_2<logical_action<Act>, X, Y> { |
260 | typedef Z type; |
261 | }; |
262 | |
263 | // or specialize the exact action |
264 | template<> |
265 | struct 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 |
271 | template<class Act> |
272 | struct plain_return_type_2<arithmetic_assignment_action<Act>, X, Y> { |
273 | typedef Z type; |
274 | }; |
275 | |
276 | // or specialize the exact action |
277 | template<> |
278 | struct 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 |
284 | template<class Act> |
285 | struct plain_return_type_2<bitwise_assignment_action<Act>, X, Y> { |
286 | typedef Z type; |
287 | }; |
288 | |
289 | // or specialize the exact action |
290 | template<> |
291 | struct plain_return_type_2<bitwise_assignment_action<and_action>, X, Y> { |
292 | typedef Y type; |
293 | }; |
294 | |
295 | // assignment |
296 | template<> |
297 | struct plain_return_type_2<other_action<assignment_action>, Assign, Assign> { |
298 | typedef void type; |
299 | }; |
300 | // subscript |
301 | template<> |
302 | struct 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 | |
312 | void 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 | |
385 | int main() { |
386 | test_unary_operators(); |
387 | test_binary_operators(); |
388 | return boost::report_errors(); |
389 | } |
390 | |