1 // Boost.Function library
3 // Copyright Douglas Gregor 2001-2003. Use, modification and
4 // distribution is subject to the Boost Software License, Version
5 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // For more information, see http://www.boost.org
10 #include <boost/test/minimal.hpp>
11 #include <boost/function.hpp>
16 using boost::function
;
21 struct write_five_obj
{ void operator()() const { global_int
= 5; } };
22 struct write_three_obj
{ int operator()() const { global_int
= 3; return 7; }};
23 static void write_five() { global_int
= 5; }
24 static void write_three() { global_int
= 3; }
25 struct generate_five_obj
{ int operator()() const { return 5; } };
26 struct generate_three_obj
{ int operator()() const { return 3; } };
27 static int generate_five() { return 5; }
28 static int generate_three() { return 3; }
29 static string
identity_str(const string
& s
) { return s
; }
30 static string
string_cat(const string
& s1
, const string
& s2
) { return s1
+s2
; }
31 static int sum_ints(int x
, int y
) { return x
+y
; }
33 struct write_const_1_nonconst_2
35 void operator()() { global_int
= 2; }
36 void operator()() const { global_int
= 1; }
41 add_to_obj(int v
) : value(v
) {}
43 int operator()(int x
) const { return value
+ x
; }
51 typedef function
<void ()> func_void_type
;
54 write_three_obj three
;
56 // Default construction
58 BOOST_CHECK(v1
.empty());
60 // Assignment to an empty function
64 // Invocation of a function
67 BOOST_CHECK(global_int
== 5);
73 // Assignment to an empty function
75 BOOST_CHECK(!v1
.empty());
77 // Invocation and self-assignment
81 BOOST_CHECK(global_int
== 3);
83 // Assignment to a non-empty function
86 // Invocation and self-assignment
90 BOOST_CHECK(global_int
== 5);
96 // Assignment to an empty function from a free function
97 v1
= BOOST_FUNCTION_TARGET_FIX(&) write_five
;
103 BOOST_CHECK(global_int
== 5);
105 // Assignment to a non-empty function from a free function
106 v1
= BOOST_FUNCTION_TARGET_FIX(&) write_three
;
107 BOOST_CHECK(!v1
.empty());
112 BOOST_CHECK(global_int
== 3);
116 BOOST_CHECK(!v1
.empty());
121 BOOST_CHECK(global_int
== 5);
123 // Assignment to a non-empty function from a free function
125 BOOST_CHECK(!v1
.empty());
130 BOOST_CHECK(global_int
== 3);
132 // Construction from another function (that is empty)
134 func_void_type
v2(v1
);
135 BOOST_CHECK(!v2
? true : false);
137 // Assignment to an empty function
139 BOOST_CHECK(!v2
.empty());
144 BOOST_CHECK(global_int
== 3);
146 // Assignment to a non-empty function
152 BOOST_CHECK(global_int
== 5);
155 BOOST_CHECK(v2
.empty());
157 // Assignment to an empty function from a free function
158 v2
= (BOOST_FUNCTION_TARGET_FIX(&) write_five
);
159 BOOST_CHECK(v2
? true : false);
164 BOOST_CHECK(global_int
== 5);
166 // Assignment to a non-empty function from a free function
167 v2
= BOOST_FUNCTION_TARGET_FIX(&) write_three
;
168 BOOST_CHECK(!v2
.empty());
173 BOOST_CHECK(global_int
== 3);
179 BOOST_CHECK(global_int
== 5);
181 BOOST_CHECK(global_int
== 3);
187 BOOST_CHECK(!v2
.empty());
192 BOOST_CHECK(global_int
== 5);
194 // Assignment to a non-empty function from a free function
196 BOOST_CHECK(!v2
.empty());
201 BOOST_CHECK(global_int
== 3);
203 // Assignment to a function from an empty function
205 BOOST_CHECK(v2
.empty());
207 // Assignment to a function from a function with a functor
210 BOOST_CHECK(!v1
.empty());
211 BOOST_CHECK(!v2
.empty());
216 BOOST_CHECK(global_int
== 3);
219 BOOST_CHECK(global_int
== 3);
221 // Assign to a function from a function with a function
222 v2
= BOOST_FUNCTION_TARGET_FIX(&) write_five
;
224 BOOST_CHECK(!v1
.empty());
225 BOOST_CHECK(!v2
.empty());
228 BOOST_CHECK(global_int
== 5);
231 BOOST_CHECK(global_int
== 5);
233 // Construct a function given another function containing a function
234 func_void_type
v3(v1
);
236 // Invocation of a function
239 BOOST_CHECK(global_int
== 5);
243 BOOST_CHECK(!v3
? true : false);
245 // Assignment to an empty function
247 BOOST_CHECK(!v3
.empty());
252 BOOST_CHECK(global_int
== 3);
254 // Assignment to a non-empty function
260 BOOST_CHECK(global_int
== 5);
264 BOOST_CHECK(v3
.empty());
266 // Assignment to an empty function from a free function
268 BOOST_CHECK(!v3
.empty());
273 BOOST_CHECK(global_int
== 5);
275 // Assignment to a non-empty function from a free function
277 BOOST_CHECK(!v3
.empty());
282 BOOST_CHECK(global_int
== 3);
286 BOOST_CHECK(!v3
.empty());
291 BOOST_CHECK(global_int
== 5);
293 // Construction of a function from a function containing a functor
294 func_void_type
v4(v3
);
296 // Invocation of a function
299 BOOST_CHECK(global_int
== 5);
303 BOOST_CHECK(v4
.empty());
305 // Assignment to an empty function
307 BOOST_CHECK(!v4
.empty());
312 BOOST_CHECK(global_int
== 3);
314 // Assignment to a non-empty function
320 BOOST_CHECK(global_int
== 5);
324 BOOST_CHECK(v4
.empty());
326 // Assignment to an empty function from a free function
328 BOOST_CHECK(!v4
.empty());
333 BOOST_CHECK(global_int
== 5);
335 // Assignment to a non-empty function from a free function
337 BOOST_CHECK(!v4
.empty());
342 BOOST_CHECK(global_int
== 3);
346 BOOST_CHECK(!v4
.empty());
351 BOOST_CHECK(global_int
== 5);
353 // Construction of a function from a functor
354 func_void_type
v5(five
);
356 // Invocation of a function
359 BOOST_CHECK(global_int
== 5);
363 BOOST_CHECK(v5
.empty());
365 // Assignment to an empty function
367 BOOST_CHECK(!v5
.empty());
372 BOOST_CHECK(global_int
== 3);
374 // Assignment to a non-empty function
380 BOOST_CHECK(global_int
== 5);
384 BOOST_CHECK(v5
.empty());
386 // Assignment to an empty function from a free function
388 BOOST_CHECK(!v5
.empty());
393 BOOST_CHECK(global_int
== 5);
395 // Assignment to a non-empty function from a free function
397 BOOST_CHECK(!v5
.empty());
402 BOOST_CHECK(global_int
== 3);
406 BOOST_CHECK(!v5
.empty());
411 BOOST_CHECK(global_int
== 5);
413 // Construction of a function from a function
414 func_void_type
v6(&write_five
);
416 // Invocation of a function
419 BOOST_CHECK(global_int
== 5);
423 BOOST_CHECK(v6
.empty());
425 // Assignment to an empty function
427 BOOST_CHECK(!v6
.empty());
432 BOOST_CHECK(global_int
== 3);
434 // Assignment to a non-empty function
440 BOOST_CHECK(global_int
== 5);
444 BOOST_CHECK(v6
.empty());
446 // Assignment to an empty function from a free function
448 BOOST_CHECK(!v6
.empty());
453 BOOST_CHECK(global_int
== 5);
455 // Assignment to a non-empty function from a free function
457 BOOST_CHECK(!v6
.empty());
462 BOOST_CHECK(global_int
== 3);
466 BOOST_CHECK(!v6
.empty());
471 BOOST_CHECK(global_int
== 5);
473 // Const vs. non-const
474 write_const_1_nonconst_2 one_or_two
;
475 const function
<void ()> v7(one_or_two
);
476 function
<void ()> v8(one_or_two
);
480 BOOST_CHECK(global_int
== 2);
484 BOOST_CHECK(global_int
== 2);
486 // Test construction from 0 and comparison to 0
487 func_void_type
v9(0);
488 BOOST_CHECK(v9
== 0);
489 BOOST_CHECK(0 == v9
);
491 // Test return values
492 typedef function
<int ()> func_int_type
;
493 generate_five_obj gen_five
;
494 generate_three_obj gen_three
;
496 func_int_type
i0(gen_five
);
498 BOOST_CHECK(i0() == 5);
500 BOOST_CHECK(i0() == 3);
502 BOOST_CHECK(i0() == 5);
503 i0
= &generate_three
;
504 BOOST_CHECK(i0() == 3);
505 BOOST_CHECK(i0
? true : false);
507 BOOST_CHECK(!i0
? true : false);
509 // Test return values with compatible types
510 typedef function
<long ()> func_long_type
;
511 func_long_type
i1(gen_five
);
513 BOOST_CHECK(i1() == 5);
515 BOOST_CHECK(i1() == 3);
517 BOOST_CHECK(i1() == 5);
518 i1
= &generate_three
;
519 BOOST_CHECK(i1() == 3);
520 BOOST_CHECK(i1
? true : false);
522 BOOST_CHECK(!i1
? true : false);
528 std::negate
<int> neg
;
530 function
<int (int)> f1(neg
);
531 BOOST_CHECK(f1(5) == -5);
533 function
<string (string
)> id(&identity_str
);
534 BOOST_CHECK(id("str") == "str");
536 function
<string (const char*)> id2(&identity_str
);
537 BOOST_CHECK(id2("foo") == "foo");
539 add_to_obj
add_to(5);
540 function
<int (int)> f2(add_to
);
541 BOOST_CHECK(f2(3) == 8);
543 const function
<int (int)> cf2(add_to
);
544 BOOST_CHECK(cf2(3) == 8);
550 function
<string (const string
&, const string
&)> cat(&string_cat
);
551 BOOST_CHECK(cat("str", "ing") == "string");
553 function
<int (short, short)> sum(&sum_ints
);
554 BOOST_CHECK(sum(2, 3) == 5);
560 function
<float ()> f1
;
561 BOOST_CHECK(f1
.empty());
563 function
<float ()> f2
;
565 BOOST_CHECK(f2
.empty());
567 function
<double ()> f3
;
569 BOOST_CHECK(f3
.empty());
573 X(int v
) : value(v
) {}
575 int twice() const { return 2*value
; }
576 int plus(int v
) { return value
+ v
; }
582 test_member_functions()
584 boost::function
<int (X
*)> f1(&X::twice
);
589 BOOST_CHECK(f1(&one
) == 2);
590 BOOST_CHECK(f1(&five
) == 10);
592 boost::function
<int (X
*)> f1_2
;
595 BOOST_CHECK(f1_2(&one
) == 2);
596 BOOST_CHECK(f1_2(&five
) == 10);
598 boost::function
<int (X
&, int)> f2(&X::plus
);
599 BOOST_CHECK(f2(one
, 3) == 4);
600 BOOST_CHECK(f2(five
, 4) == 9);
603 struct add_with_throw_on_copy
{
604 int operator()(int x
, int y
) const { return x
+y
; }
606 add_with_throw_on_copy() {}
608 add_with_throw_on_copy(const add_with_throw_on_copy
&)
610 throw std::runtime_error("But this CAN'T throw");
613 add_with_throw_on_copy
& operator=(const add_with_throw_on_copy
&)
615 throw std::runtime_error("But this CAN'T throw");
622 add_with_throw_on_copy atc
;
624 boost::function
<int (int, int)> f(boost::ref(atc
));
625 BOOST_CHECK(f(1, 3) == 4);
627 catch(std::runtime_error e
) {
628 BOOST_ERROR("Nonthrowing constructor threw an exception");
632 static void dummy() {}
634 static void test_empty_ref()
636 boost::function
<void()> f1
;
637 boost::function
<void()> f2(boost::ref(f1
));
641 BOOST_ERROR("Exception didn't throw for reference to empty function.");
643 catch(std::runtime_error e
) {}
650 catch(std::runtime_error e
) {
651 BOOST_ERROR("Error calling referenced function.");
656 static void test_exception()
658 boost::function
<int (int, int)> f
;
663 catch(boost::bad_function_call
) {
668 typedef boost::function
< void * (void * reader
) > reader_type
;
669 typedef std::pair
<int, reader_type
> mapped_type
;
671 static void test_implicit()
677 static void test_call_obj(boost::function
<int (int, int)> f
)
679 BOOST_CHECK(!f
.empty());
682 static void test_call_cref(const boost::function
<int (int, int)>& f
)
684 BOOST_CHECK(!f
.empty());
687 static void test_call()
689 test_call_obj(std::plus
<int>());
690 test_call_cref(std::plus
<int>());
693 struct big_aggregating_structure
{
694 int disable_small_objects_optimizations
[32];
696 big_aggregating_structure()
701 big_aggregating_structure(const big_aggregating_structure
&)
706 ~big_aggregating_structure()
722 template <class FunctionT
>
723 static void test_move_semantics()
725 typedef FunctionT f1_type
;
727 big_aggregating_structure obj
;
733 BOOST_CHECK(!f1
.empty());
734 BOOST_CHECK(global_int
== 1);
736 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
737 // Testing rvalue constructors
738 f1_type
f2(static_cast<f1_type
&&>(f1
));
739 BOOST_CHECK(f1
.empty());
740 BOOST_CHECK(!f2
.empty());
741 BOOST_CHECK(global_int
== 1);
743 BOOST_CHECK(global_int
== 2);
745 f1_type
f3(static_cast<f1_type
&&>(f2
));
746 BOOST_CHECK(f1
.empty());
747 BOOST_CHECK(f2
.empty());
748 BOOST_CHECK(!f3
.empty());
749 BOOST_CHECK(global_int
== 2);
751 BOOST_CHECK(global_int
== 3);
753 // Testing move assignment
755 BOOST_CHECK(f4
.empty());
756 f4
= static_cast<f1_type
&&>(f3
);
757 BOOST_CHECK(f1
.empty());
758 BOOST_CHECK(f2
.empty());
759 BOOST_CHECK(f3
.empty());
760 BOOST_CHECK(!f4
.empty());
761 BOOST_CHECK(global_int
== 3);
763 BOOST_CHECK(global_int
== 4);
765 // Testing self move assignment
766 f4
= static_cast<f1_type
&&>(f4
);
767 BOOST_CHECK(!f4
.empty());
768 BOOST_CHECK(global_int
== 4);
770 // Testing, that no memory leaked when assigning to nonempty function
772 BOOST_CHECK(!f4
.empty());
773 BOOST_CHECK(global_int
== 4);
775 BOOST_CHECK(global_int
== 5);
776 f4
= static_cast<f1_type
&&>(f5
);
777 BOOST_CHECK(global_int
== 4);
782 int test_main(int, char* [])
788 test_member_functions();
794 test_move_semantics
<function
<void()> >();
795 test_move_semantics
<boost::function0
<void> >();