• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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