1 // Copyright 2014 Antony Polukhin.
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 // For more information, see http://www.boost.org
8 
9 #include <boost/function.hpp>
10 #include <boost/move/move.hpp>
11 #include <boost/core/lightweight_test.hpp>
12 #include <iostream>
13 #include <cstdlib>
14 
15 #define BOOST_CHECK BOOST_TEST
16 
17 class only_movable {
18 private:
19     BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable)
20     int value_;
21     bool moved_;
22 
23 public:
only_movable(BOOST_RV_REF (only_movable)x)24     only_movable(BOOST_RV_REF(only_movable) x)
25         : value_(x.value_)
26         , moved_(false)
27     {
28         x.moved_ = true;
29     }
30 
operator =(BOOST_RV_REF (only_movable)x)31    only_movable& operator=(BOOST_RV_REF(only_movable) x) {
32         value_ = x.value_;
33         x.moved_ = true;
34         moved_ = false;
35         return *this;
36    }
37 
only_movable(int value=0)38     explicit only_movable(int value = 0) : value_(value), moved_(false) {}
get_value() const39     int get_value() const {  return value_;  }
is_moved() const40     bool is_moved() const { return moved_; }
41 };
42 
43 
one(BOOST_RV_REF (only_movable)v)44 int one(BOOST_RV_REF(only_movable) v) { return v.get_value(); }
two(BOOST_RV_REF (only_movable)t)45 only_movable two(BOOST_RV_REF(only_movable) t) {
46     only_movable t1 = boost::move(t);
47     return BOOST_MOVE_RET(only_movable, t1);
48 }
49 
two_sum(BOOST_RV_REF (only_movable)t1,BOOST_RV_REF (only_movable)t2)50 only_movable two_sum(BOOST_RV_REF(only_movable) t1, BOOST_RV_REF(only_movable) t2) {
51     only_movable ret(t1.get_value() + t2.get_value());
52     return BOOST_MOVE_RET(only_movable, ret);
53 }
54 
55 struct sum_struct {
operator ()sum_struct56     only_movable operator()(BOOST_RV_REF(only_movable) t1, BOOST_RV_REF(only_movable) t2) const {
57         only_movable ret(t1.get_value() + t2.get_value());
58         return BOOST_MOVE_RET(only_movable, ret);
59     }
60 };
61 
62 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
three(std::string &&)63 int three(std::string&&) { return 1; }
four(std::string && s)64 std::string&& four(std::string&& s) { return boost::move(s); }
65 #endif
66 
main()67 int main()
68 {
69     using boost::function;
70 
71     function <int(BOOST_RV_REF(only_movable))>  f1 = one;
72 
73     only_movable om1(1);
74     BOOST_CHECK(f1(boost::move(om1)) == 1);
75 
76     function <only_movable(BOOST_RV_REF(only_movable))>  f2 = two;
77 
78     only_movable om2(2);
79     only_movable om2_2 = f2(boost::move(om2));
80     BOOST_CHECK(om2_2.get_value() == 2);
81     BOOST_CHECK(om2.is_moved());
82 
83     {
84         function <only_movable(BOOST_RV_REF(only_movable), BOOST_RV_REF(only_movable))>  f2_sum = two_sum;
85         only_movable om1_sum(1), om2_sum(2);
86         only_movable om2_sum_2 = f2_sum(boost::move(om1_sum), boost::move(om2_sum));
87         BOOST_CHECK(om2_sum_2.get_value() == 3);
88     }
89 
90     {
91         sum_struct s;
92         function <only_movable(BOOST_RV_REF(only_movable), BOOST_RV_REF(only_movable))>  f2_sum = s;
93         only_movable om1_sum(1), om2_sum(2);
94         only_movable om2_sum_2 = f2_sum(boost::move(om1_sum), boost::move(om2_sum));
95         BOOST_CHECK(om2_sum_2.get_value() == 3);
96     }
97 
98 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
99     function <int(std::string&&)>               f3 = three;
100     function <std::string&& (std::string&& s)>  f4 = four;
101 
102     f3(std::string("Hello"));
103     BOOST_CHECK(f4(std::string("world")) == "world");
104 #endif
105 
106     return boost::report_errors();
107 }
108