]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/lambda/test/bind_tests_advanced.cpp
1 // bind_tests_advanced.cpp -- The Boost Lambda Library ------------------
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
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)
11 // For more information, see www.boost.org
13 // -----------------------------------------------------------------------
16 #include <boost/test/minimal.hpp> // see "Header Implementation Option"
18 #include "boost/lambda/lambda.hpp"
19 #include "boost/lambda/bind.hpp"
22 #include "boost/any.hpp"
23 #include "boost/type_traits/is_reference.hpp"
24 #include "boost/mpl/assert.hpp"
25 #include "boost/mpl/if.hpp"
34 using namespace boost::lambda
;
35 namespace bl
= boost::lambda
;
37 int sum_0() { return 0; }
38 int sum_1(int a
) { return a
; }
39 int sum_2(int a
, int b
) { return a
+b
; }
41 int product_2(int a
, int b
) { return a
*b
; }
43 // unary function that returns a pointer to a binary function
44 typedef int (*fptr_type
)(int, int);
45 fptr_type
sum_or_product(bool x
) {
46 return x
? sum_2
: product_2
;
49 // a nullary functor that returns a pointer to a unary function that
50 // returns a pointer to a binary function.
52 typedef fptr_type (*result_type
)(bool x
);
53 template <class T
> struct sig
{ typedef result_type type
; };
55 result_type
operator()() const { return sum_or_product
; }
58 void test_nested_binds()
62 // bind calls can be nested (the target function can be a lambda functor)
63 // The interpretation is, that the innermost lambda functor returns something
64 // that is bindable (another lambda functor, function pointer ...)
68 BOOST_CHECK(bind(bind(&sum_or_product
, _1
), 1, 2)(condition
)==3);
69 BOOST_CHECK(bind(bind(&sum_or_product
, _1
), _2
, _3
)(condition
, j
, k
)==5);
72 BOOST_CHECK(bind(bind(&sum_or_product
, _1
), 1, 2)(condition
)==2);
73 BOOST_CHECK(bind(bind(&sum_or_product
, _1
), _2
, _3
)(condition
, j
, k
)==6);
77 BOOST_CHECK(bind(bind(bind(wo
), _1
), _2
, _3
)(condition
, j
, k
)==6);
84 // unlambda -------------------------------------------------
86 // Sometimes it may be necessary to prevent the argument substitution of
87 // taking place. For example, we may end up with a nested bind expression
88 // inadvertently when using the target function is received as a parameter
91 int call_with_100(const F
& f
) {
95 // bind(f, _1)(make_const(100));
96 // This would result in;
97 // bind(_1 + 1, _1)(make_const(100)) , which would be a compile time error
99 return bl::bind(unlambda(f
), _1
)(make_const(100));
101 // for other functors than lambda functors, unlambda has no effect
102 // (except for making them const)
106 int call_with_101(const F
& f
) {
108 return bind(unlambda(f
), _1
)(make_const(101));
113 void test_unlambda() {
117 BOOST_CHECK(unlambda(_1
+ _2
)(i
, i
) == 2);
118 BOOST_CHECK(unlambda(++var(i
))() == 2);
119 BOOST_CHECK(call_with_100(_1
+ 1) == 101);
122 BOOST_CHECK(call_with_101(_1
+ 1) == 102);
124 BOOST_CHECK(call_with_100(bl::bind(std_functor(std::bind1st(std::plus
<int>(), 1)), _1
)) == 101);
126 // std_functor insturcts LL that the functor defines a result_type typedef
127 // rather than a sig template.
128 bl::bind(std_functor(std::plus
<int>()), _1
, _2
)(i
, i
);
134 // protect ------------------------------------------------------------
136 // protect protects a lambda functor from argument substitution.
137 // protect is useful e.g. with nested stl algorithm calls.
143 // note, std::for_each returns it's last argument
144 // We want the same behaviour from our ll::for_each.
145 // However, the functor can be called with any arguments, and
146 // the return type thus depends on the argument types.
148 // 1. Provide a sig class member template:
150 // The return type deduction system instantiate this class as:
151 // sig<Args>::type, where Args is a boost::tuples::cons-list
152 // The head type is the function object type itself
153 // cv-qualified (so it is possilbe to provide different return types
154 // for differently cv-qualified operator()'s.
156 // The tail type is the list of the types of the actual arguments the
157 // function was called with.
158 // So sig should contain a typedef type, which defines a mapping from
159 // the operator() arguments to its return type.
160 // Note, that it is possible to provide different sigs for the same functor
161 // if the functor has several operator()'s, even if they have different
162 // number of arguments.
164 // Note, that the argument types in Args are guaranteed to be non-reference
165 // types, but they can have cv-qualifiers.
167 template <class Args
>
169 typedef typename
boost::remove_const
<
170 typename
boost::tuples::element
<3, Args
>::type
174 template <class A
, class B
, class C
>
176 operator()(const A
& a
, const B
& b
, const C
& c
) const
177 { return std::for_each(a
, b
, c
);}
180 } // end of ll namespace
188 for(int j
=0; j
<3; ++j
) a
[j
] = b
[j
];
190 std::for_each(a
, a
+3,
191 bind(ll::for_each(), _1
, _1
+ 5, protect(_1
= ++var(i
))));
193 // This is how you could output the values (it is uncommented, no output
194 // from a regression test file):
195 // std::for_each(a, a+3,
196 // bind(ll::for_each(), _1, _1 + 5,
197 // std::cout << constant("\nLine ") << (&_1 - a) << " : "
204 std::for_each(a
, a
+3,
205 bind(ll::for_each(), _1
, _1
+ 5,
208 BOOST_CHECK(sum
== (1+15)*15/2);
212 std::for_each(a
, a
+3,
213 bind(ll::for_each(), _1
, _1
+ 5,
214 sum
+= 1 + protect(_1
)) // add element count
216 BOOST_CHECK(sum
== (1+15)*15/2 + 15);
218 (1 + protect(_1
))(sum
);
221 ((k
+= constant(1)) += protect(constant(2)))();
225 ((k
+= constant(1)) += protect(constant(2)))()();
228 // note, the following doesn't work:
230 // ((var(k) = constant(1)) = protect(constant(2)))();
232 // (var(k) = constant(1))() returns int& and thus the
233 // second assignment fails.
235 // We should have something like:
236 // bind(var, var(k) = constant(1)) = protect(constant(2)))();
237 // But currently var is not bindable.
239 // The same goes with ret. A bindable ret could be handy sometimes as well
240 // (protect(std::cout << _1), std::cout << _1)(i)(j); does not work
241 // because the comma operator tries to store the result of the evaluation
242 // of std::cout << _1 as a copy (and you can't copy std::ostream).
243 // something like this:
244 // (protect(std::cout << _1), bind(ref, std::cout << _1))(i)(j);
247 // the stuff below works, but we do not want extra output to
248 // cout, must be changed to stringstreams but stringstreams do not
249 // work due to a bug in the type deduction. Will be fixed...
251 // But for now, ref is not bindable. There are other ways around this:
254 (protect(std::cout
<< _1
), (std::cout
<< _1
, 0))(x
)(y
);
256 // added one dummy value to make the argument to comma an int
257 // instead of ostream&
259 // Note, the same problem is more apparent without protect
260 // (std::cout << 1, std::cout << constant(2))(); // does not work
262 (boost::ref(std::cout
<< 1), std::cout
<< constant(2))(); // this does
269 void test_lambda_functors_as_arguments_to_lambda_functors() {
271 // lambda functor is a function object, and can therefore be used
272 // as an argument to another lambda functors function call object.
274 // Note however, that the argument/type substitution is not entered again.
275 // This means, that something like this will not work:
277 (_1
+ _2
)(_1
, make_const(7));
278 (_1
+ _2
)(bind(&sum_0
), make_const(7));
280 // or it does work, but the effect is not to call
281 // sum_0() + 7, but rather
282 // bind(sum_0) + 7, which results in another lambda functor
283 // (lambda functor + int) and can be called again
284 BOOST_CHECK((_1
+ _2
)(bind(&sum_0
), make_const(7))() == 7);
287 BOOST_CHECK((_1
- _2
)(_2
, _1
)(i
, j
) == j
- i
);
289 // also, note that lambda functor are no special case for bind if received
290 // as a parameter. In oder to be bindable, the functor must
291 // defint the sig template, or then
292 // the return type must be defined within the bind call. Lambda functors
293 // do define the sig template, so if the return type deduction system
294 // covers the case, there is no need to specify the return type
299 // Let type deduction find out the return type
300 BOOST_CHECK(bind(_1
, _2
, _3
)(unlambda(_1
+ _2
), a
, b
) == 11);
302 //specify it yourself:
303 BOOST_CHECK(bind(_1
, _2
, _3
)(ret
<int>(_1
+ _2
), a
, b
) == 11);
304 BOOST_CHECK(ret
<int>(bind(_1
, _2
, _3
))(_1
+ _2
, a
, b
) == 11);
305 BOOST_CHECK(bind
<int>(_1
, _2
, _3
)(_1
+ _2
, a
, b
) == 11);
313 void test_const_parameters() {
315 // (_1 + _2)(1, 2); // this would fail,
317 // Either make arguments const:
318 BOOST_CHECK((_1
+ _2
)(make_const(1), make_const(2)) == 3);
320 // Or use const_parameters:
321 BOOST_CHECK(const_parameters(_1
+ _2
)(1, 2) == 3);
327 void test_rvalue_arguments()
329 // Not quite working yet.
330 // Problems with visual 7.1
331 // BOOST_CHECK((_1 + _2)(1, 2) == 3);
334 void test_break_const()
337 // break_const is currently unnecessary, as LL supports perfect forwarding
338 // for up to there argument lambda functors, and LL does not support
339 // lambda functors with more than 3 args.
341 // I'll keep the test case around anyway, if more arguments will be supported
346 // break_const breaks constness! Be careful!
347 // You need this only if you need to have side effects on some argument(s)
348 // and some arguments are non-const rvalues and your lambda functors
349 // take more than 3 arguments.
353 // OLD COMMENT: (_1 += _2)(i, 2) // fails, 2 is a non-const rvalue
354 // OLD COMMENT: const_parameters(_1 += _2)(i, 2) // fails, side-effect to i
355 break_const(_1
+= _2
)(i
, 2); // ok
363 typedef typename
boost::tuples::element
<1, Args
>::type arg1
;
364 // If the argument type is not the same as the expected type,
365 // return void, which will cause an error. Note that we
366 // can't just assert that the types are the same, because
367 // both const and non-const versions can be instantiated
368 // even though only one is ultimately used.
369 typedef typename
boost::mpl::if_
<boost::is_same
<arg1
, T
>,
370 typename
boost::remove_const
<arg1
>::type
,
375 U
operator()(const U
& arg
) const {
383 BOOST_CHECK(bind(func
<int>(), 1)() == 1);
384 BOOST_CHECK(bind(func
<const int>(), _1
)(static_cast<const int&>(i
)) == 1);
385 BOOST_CHECK(bind(func
<int>(), _1
)(i
) == 1);
390 virtual int foo() = 0;
393 class derived
: public base
{
404 BOOST_CHECK(bind(&base::foo
, var(b
))() == 1);
405 BOOST_CHECK(bind(&base::foo
, *_1
)(&b
) == 1);
408 int test_main(int, char *[]) {
413 test_lambda_functors_as_arguments_to_lambda_functors();
414 test_const_parameters();
415 test_rvalue_arguments();