1 // bind_tests_advanced.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 // Copyright (C) 2010 Steven Watanabe
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // For more information, see www.boost.org
12
13 // -----------------------------------------------------------------------
14
15
16 #include <boost/core/lightweight_test.hpp>
17
18 /*
19 #include "boost/lambda/lambda.hpp"
20 #include "boost/lambda/bind.hpp"
21 */
22 #include <boost/phoenix/core.hpp>
23 #include <boost/phoenix/operator.hpp>
24 #include <boost/phoenix/bind.hpp>
25 #include <boost/phoenix/scope.hpp>
26
27 #include "boost/any.hpp"
28 #include "boost/type_traits/is_reference.hpp"
29 #include "boost/mpl/assert.hpp"
30 #include "boost/mpl/if.hpp"
31
32 #include <iostream>
33
34 #include <functional>
35
36 #include <algorithm>
37
38 namespace phoenix = boost::phoenix;
39
sum_0()40 int sum_0() { return 0; }
sum_1(int a)41 int sum_1(int a) { return a; }
sum_2(int a,int b)42 int sum_2(int a, int b) { return a+b; }
43
product_2(int a,int b)44 int product_2(int a, int b) { return a*b; }
45
46 // unary function that returns a pointer to a binary function
47 typedef int (*fptr_type)(int, int);
sum_or_product(bool x)48 fptr_type sum_or_product(bool x) {
49 return x ? sum_2 : product_2;
50 }
51
52 // a nullary functor that returns a pointer to a unary function that
53 // returns a pointer to a binary function.
54 struct which_one {
55 typedef fptr_type (*result_type)(bool x);
56
57 // Was:
58 // template <class T> struct sig { typedef result_type type; };
59 // phoenix follows the standard result_of protocol
60
operator ()which_one61 result_type operator()() const { return sum_or_product; }
62 };
63
test_nested_binds()64 void test_nested_binds()
65 {
66 using phoenix::bind;
67 using phoenix::placeholders::_1;
68 using phoenix::placeholders::_2;
69 using phoenix::placeholders::_3;
70 int j = 2; int k = 3;
71
72 // bind calls can be nested (the target function can be a lambda functor)
73 // The interpretation is, that the innermost lambda functor returns something
74 // that is bindable (another lambda functor, function pointer ...)
75 bool condition;
76
77 condition = true;
78 BOOST_TEST_EQ(bind(bind(&sum_or_product, _1), 1, 2)(condition), 3);
79 BOOST_TEST_EQ(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k), 5);
80
81 condition = false;
82 BOOST_TEST_EQ(bind(bind(&sum_or_product, _1), 1, 2)(condition), 2);
83 BOOST_TEST_EQ(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k), 6);
84
85
86 which_one wo;
87 BOOST_TEST_EQ(bind(bind(bind(wo), _1), _2, _3)(condition, j, k), 6);
88
89
90 return;
91 }
92
93
94 // unlambda -------------------------------------------------
95
96 // Sometimes it may be necessary to prevent the argument substitution of
97 // taking place. For example, we may end up with a nested bind expression
98 // inadvertently when using the target function is received as a parameter
99
100 template<class F>
call_with_100(const F & f)101 int call_with_100(const F& f) {
102
103
104
105 // bind(f, _1)(make_const(100));
106 // This would result in;
107 // bind(_1 + 1, _1)(make_const(100)) , which would be a compile time error
108
109 //return bl::bind(unlambda(f), _1)(make_const(100));
110 return 5;
111
112 // for other functors than lambda functors, unlambda has no effect
113 // (except for making them const)
114 }
115
116 template<class F>
call_with_101(const F & f)117 int call_with_101(const F& f) {
118
119 //return bind(unlambda(f), _1)(make_const(101));
120 return 5;
121
122 }
123
124
test_unlambda()125 void test_unlambda() {
126
127 using phoenix::placeholders::_1;
128 using phoenix::placeholders::_2;
129
130 int i = 1;
131
132 //BOOST_TEST_EQ(unlambda(_1 + _2)(i, i), 2);
133 //BOOST_TEST_EQ(unlambda(++var(i))(), 2);
134 //BOOST_TEST_EQ(call_with_100(_1 + 1), 101);
135
136
137 //BOOST_TEST_EQ(call_with_101(_1 + 1), 102);
138
139 //BOOST_TEST_EQ(call_with_100(bl::bind(std_functor(std::bind1st(std::plus<int>(), 1)), _1)), 101);
140
141 // Was:
142 // std_functor insturcts LL that the functor defines a result_type typedef
143 // rather than a sig template.
144 //bl::bind(std_functor(std::plus<int>()), _1, _2)(i, i);
145 // Standard functors can be used without any further action needed.
146 phoenix::bind(std::plus<int>(), _1, _2)(i, i);
147 }
148
149
150
151
152 // protect ------------------------------------------------------------
153
154 // protect protects a lambda functor from argument substitution.
155 // protect is useful e.g. with nested stl algorithm calls.
156
157 #if 0
158 namespace ll {
159
160 struct for_each {
161
162 // Was:
163 // note, std::for_each returns it's last argument
164 // We want the same behaviour from our ll::for_each.
165 // However, the functor can be called with any arguments, and
166 // the return type thus depends on the argument types.
167
168 // 1. Provide a sig class member template:
169
170 // The return type deduction system instantiate this class as:
171 // sig<Args>::type, where Args is a boost::tuples::cons-list
172 // The head type is the function object type itself
173 // cv-qualified (so it is possilbe to provide different return types
174 // for differently cv-qualified operator()'s.
175
176 // The tail type is the list of the types of the actual arguments the
177 // function was called with.
178 // So sig should contain a typedef type, which defines a mapping from
179 // the operator() arguments to its return type.
180 // Note, that it is possible to provide different sigs for the same functor
181 // if the functor has several operator()'s, even if they have different
182 // number of arguments.
183
184 // Note, that the argument types in Args are guaranteed to be non-reference
185 // types, but they can have cv-qualifiers.
186
187 // template <class Args>
188 //struct sig {
189 // typedef typename boost::remove_const<
190 // typename boost::tuples::element<3, Args>::type
191 // >::type type;
192 //};
193
194 // We follow the result_of protocol ...
195 template <typename Sig>
196 struct result;
197
198 template <typename This, typename A, typename B, typename C>
199 struct result<This(A&,B&,C&)>
200 {typedef C type;};
201
202 template <class A, class B, class C>
203 C
204 operator()(const A& a, const B& b, const C& c) const
205 { return std::for_each(a, b, c);}
206 };
207
208 } // end of ll namespace
209 #endif
210
test_protect()211 void test_protect()
212 {
213 using phoenix::placeholders::_1;
214 int i = 0;
215 int b[3][5];
216 int* a[3];
217
218 for(int j=0; j<3; ++j) a[j] = b[j];
219
220 // Was:
221 //std::for_each(a, a+3,
222 // bind(ll::for_each(), _1, _1 + 5, protect(_1 = ++var(i))));
223 #if 0
224 std::for_each(a, a+3,
225 phoenix::bind(ll::for_each(), _1, _1 + 5, phoenix::lambda[_1 = ++phoenix::ref(i)]));
226 #endif
227
228
229 // This is how you could output the values (it is uncommented, no output
230 // from a regression test file):
231 // std::for_each(a, a+3,
232 // bind(ll::for_each(), _1, _1 + 5,
233 // std::cout << constant("\nLine ") << (&_1 - a) << " : "
234 // << protect(_1)
235 // )
236 // );
237
238 int sum = 0;
239
240 // Was:
241 //std::for_each(a, a+3,
242 // bind(ll::for_each(), _1, _1 + 5,
243 // protect(sum += _1))
244 // );
245 #if 0
246 std::for_each(a, a+3,
247 phoenix::bind(ll::for_each(), _1, _1 + 5,
248 phoenix::lambda[phoenix::ref(sum) += _1])
249 );
250 BOOST_TEST_EQ(sum, (1+15)*15/2);
251 #endif
252
253 sum = 0;
254
255 // Was:
256 //std::for_each(a, a+3,
257 // bind(ll::for_each(), _1, _1 + 5,
258 // sum += 1 + protect(_1)) // add element count
259 // );
260 #if 0
261 std::for_each(a, a+3,
262 phoenix::bind(ll::for_each(), _1, _1 + 5,
263 phoenix::ref(sum) += 1 + phoenix::lambda[_1]) // add element count
264 );
265 BOOST_TEST_EQ(sum, (1+15)*15/2 + 15);
266 #endif
267
268 // Was:
269 //(1 + protect(_1))(sum);
270 (1 + phoenix::lambda[_1])(sum);
271
272 int k = 0;
273 // Was:
274 //((k += constant(1)) += protect(constant(2)))();
275 ((phoenix::ref(k) += 1) += phoenix::lambda[phoenix::cref(2)])();
276 BOOST_TEST_EQ(k, 1);
277
278 k = 0;
279 // Was:
280 //((k += constant(1)) += protect(constant(2)))()();
281 //((phoenix::ref(k) += 1) += phoenix::lambda[std::cout << phoenix::cref("ok ...\n"), phoenix::cref(2)])()();
282 //std::cout << ((phoenix::ref(k) += 1) + phoenix::lambda[phoenix::cref(2)])()() << "\n";
283 ((phoenix::ref(k) += 1) += 2)();
284 std::cout << k << "\n";
285 BOOST_TEST_EQ(k, 3);
286
287 // note, the following doesn't work:
288
289 // ((var(k) = constant(1)) = protect(constant(2)))();
290
291 // (var(k) = constant(1))() returns int& and thus the
292 // second assignment fails.
293
294 // We should have something like:
295 // bind(var, var(k) = constant(1)) = protect(constant(2)))();
296 // But currently var is not bindable.
297
298 // The same goes with ret. A bindable ret could be handy sometimes as well
299 // (protect(std::cout << _1), std::cout << _1)(i)(j); does not work
300 // because the comma operator tries to store the result of the evaluation
301 // of std::cout << _1 as a copy (and you can't copy std::ostream).
302 // something like this:
303 // (protect(std::cout << _1), bind(ref, std::cout << _1))(i)(j);
304
305
306 // the stuff below works, but we do not want extra output to
307 // cout, must be changed to stringstreams but stringstreams do not
308 // work due to a bug in the type deduction. Will be fixed...
309 #if 0
310 // But for now, ref is not bindable. There are other ways around this:
311
312 int x = 1, y = 2;
313 (protect(std::cout << _1), (std::cout << _1, 0))(x)(y);
314
315 // added one dummy value to make the argument to comma an int
316 // instead of ostream&
317
318 // Note, the same problem is more apparent without protect
319 // (std::cout << 1, std::cout << constant(2))(); // does not work
320
321 (boost::ref(std::cout << 1), std::cout << constant(2))(); // this does
322
323 #endif
324
325 }
326
327
test_lambda_functors_as_arguments_to_lambda_functors()328 void test_lambda_functors_as_arguments_to_lambda_functors() {
329 using phoenix::bind;
330 using phoenix::cref;
331 using phoenix::placeholders::_1;
332 using phoenix::placeholders::_2;
333 using phoenix::placeholders::_3;
334
335 // lambda functor is a function object, and can therefore be used
336 // as an argument to another lambda functors function call object.
337
338 // Note however, that the argument/type substitution is not entered again.
339 // This means, that something like this will not work:
340
341 (_1 + _2)(_1, cref(7));
342 (_1 + _2)(bind(&sum_0), cref(7));
343
344 // or it does work, but the effect is not to call
345 // sum_0() + 7, but rather
346 // bind(sum_0) + 7, which results in another lambda functor
347 // (lambda functor + int) and can be called again
348 BOOST_TEST_EQ((_1 + _2)(bind(&sum_0), cref(7))(), 7);
349
350 int i = 3, j = 12;
351 BOOST_TEST_EQ((_1 - _2)(_2, _1)(i, j), j - i);
352
353 // also, note that lambda functor are no special case for bind if received
354 // as a parameter. In oder to be bindable, the functor must
355 // defint the sig template, or then
356 // the return type must be defined within the bind call. Lambda functors
357 // do define the sig template, so if the return type deduction system
358 // covers the case, there is no need to specify the return type
359 // explicitly.
360
361 int a = 5, b = 6;
362
363 // Let type deduction find out the return type
364 //BOOST_TEST_EQ(bind(_1, _2, _3)(unlambda(_1 + _2), a, b), 11);
365
366 //specify it yourself:
367 BOOST_TEST_EQ(bind(_1, _2, _3)(_1 + _2, a, b), 11);
368
369 bind(_1,1.0)(_1+_1);
370 return;
371
372 }
373 /*
374 template<class T>
375 struct func {
376 template<class Args>
377 struct sig {
378 typedef typename boost::tuples::element<1, Args>::type arg1;
379 // If the argument type is not the same as the expected type,
380 // return void, which will cause an error. Note that we
381 // can't just assert that the types are the same, because
382 // both const and non-const versions can be instantiated
383 // even though only one is ultimately used.
384 typedef typename boost::mpl::if_<boost::is_same<arg1, T>,
385 typename boost::remove_const<arg1>::type,
386 void
387 >::type type;
388 };
389 template<class U>
390 U operator()(const U& arg) const {
391 return arg;
392 }
393 };
394
395 void test_sig()
396 {
397 int i = 1;
398 BOOST_TEST_EQ(bind(func<int>(), 1)(), 1);
399 BOOST_TEST_EQ(bind(func<const int>(), _1)(static_cast<const int&>(i)), 1);
400 BOOST_TEST_EQ(bind(func<int>(), _1)(i), 1);
401 }
402
403 class base {
404 public:
405 virtual int foo() = 0;
406 };
407
408 class derived : public base {
409 public:
410 virtual int foo() {
411 return 1;
412 }
413 };
414
415 void test_abstract()
416 {
417 derived d;
418 base& b = d;
419 BOOST_TEST_EQ(bind(&base::foo, var(b))(), 1);
420 BOOST_TEST_EQ(bind(&base::foo, *_1)(&b), 1);
421 }
422 */
423
main()424 int main()
425 {
426 test_nested_binds();
427 test_unlambda();
428 test_protect();
429 test_lambda_functors_as_arguments_to_lambda_functors();
430 //test_sig();
431 //test_abstract();
432 return boost::report_errors();
433 }
434