1 /*=============================================================================
2 Copyright (c) 2005-2006 Joao Abecasis
3 Copyright (c) 2006-2007 Tobias Schwinger
4
5 Use modification and distribution are subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt).
8 ==============================================================================*/
9
10 #include <boost/fusion/functional/invocation/invoke_function_object.hpp>
11 #include <boost/detail/lightweight_test.hpp>
12
13 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
14 #include <functional>
15 #endif
16
17 #include <boost/type_traits/is_same.hpp>
18
19 #include <memory>
20 #include <boost/noncopyable.hpp>
21
22 #include <boost/mpl/int.hpp>
23
24 #include <boost/fusion/container/vector.hpp>
25 #include <boost/fusion/container/list.hpp>
26 #include <boost/fusion/sequence/intrinsic/size.hpp>
27 #include <boost/fusion/sequence/intrinsic/begin.hpp>
28 #include <boost/fusion/view/single_view.hpp>
29 #include <boost/fusion/view/iterator_range.hpp>
30 #include <boost/fusion/iterator/advance.hpp>
31 #include <boost/fusion/algorithm/transformation/join.hpp>
32
33 #include "../compile_time/sfinae_friendly.hpp"
34
35 namespace mpl = boost::mpl;
36 namespace fusion = boost::fusion;
37
38 template <typename T>
const_(T const & t)39 inline T const & const_(T const & t)
40 {
41 return t;
42 }
43
44 struct object {};
45 struct object_nc : boost::noncopyable {};
46
47 struct fobj
48 {
49 // Handle nullary separately to exercise result_of support
50 template <typename Sig>
51 struct result;
52
53 template <class Self, typename T0>
54 struct result< Self(T0) >
55 {
56 typedef int type;
57 };
58
59 template <class Self, typename T0, typename T1>
60 struct result< Self(T0, T1) >
61 {
62 typedef int type;
63 };
64
65 template <class Self, typename T0, typename T1, typename T2>
66 struct result< Self(T0, T1, T2) >
67 {
68 typedef int type;
69 };
70
operator ()fobj71 int operator()() { return 0; }
operator ()fobj72 int operator()() const { return 1; }
73
operator ()fobj74 int operator()(int i) { return 2 + i; }
operator ()fobj75 int operator()(int i) const { return 3 + i; }
76
operator ()fobj77 int operator()(int i, object &) { return 4 + i; }
operator ()fobj78 int operator()(int i, object &) const { return 5 + i; }
operator ()fobj79 int operator()(int i, object const &) { return 6 + i; }
operator ()fobj80 int operator()(int i, object const &) const { return 7 + i; }
81
operator ()fobj82 int operator()(int i, object &, object_nc &) { return 10 + i; }
operator ()fobj83 int operator()(int i, object &, object_nc &) const { return 11 + i; }
84 int operator()(int i, object const &, object_nc &);
85 int operator()(int i, object const &, object_nc &) const;
86 };
87 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v1>));
88 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v2>));
89 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v3>));
90
91 struct nullary_fobj
92 {
93 typedef int result_type;
94
operator ()nullary_fobj95 int operator()() { return 0; }
operator ()nullary_fobj96 int operator()() const { return 1; }
97 };
98 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v1>));
99 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v2>));
100 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v3>));
101
102 struct fobj_nc
103 : boost::noncopyable
104 {
105 // Handle nullary separately to exercise result_of support
106 template <typename T>
107 struct result;
108
109 template <class Self, typename T0>
110 struct result< Self(T0) >
111 {
112 typedef int type;
113 };
114
operator ()fobj_nc115 int operator()(int i) { return 14 + i; }
operator ()fobj_nc116 int operator()(int i) const { return 15 + i; }
117 };
118 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v0>));
119 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v1>));
120 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v2>));
121 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v3>));
122
123 struct nullary_fobj_nc
124 : boost::noncopyable
125 {
126 typedef int result_type;
127
operator ()nullary_fobj_nc128 int operator()() { return 12; }
operator ()nullary_fobj_nc129 int operator()() const { return 13; }
130 };
131 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v1>));
132 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v2>));
133 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v3>));
134
135
136 typedef int element1_type;
137 typedef object element2_type;
138 typedef object_nc & element3_type;
139
140 int element1 = 100;
141 object element2 = object();
142 object_nc element3;
143
144 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<0>)145 void test_sequence_n(Sequence & seq, mpl::int_<0>)
146 {
147 // Function Objects
148
149 nullary_fobj f;
150 BOOST_TEST(f () == fusion::invoke_function_object(f , seq ));
151 BOOST_TEST(f () == fusion::invoke_function_object(f , const_(seq)));
152
153 // Note: The function object is taken by value, so we request the copy
154 // to be const with an explicit template argument. We can also request
155 // the function object to be pased by reference...
156 BOOST_TEST(const_(f)() == fusion::invoke_function_object<nullary_fobj const >(const_(f), seq ));
157 BOOST_TEST(const_(f)() == fusion::invoke_function_object<nullary_fobj const &>(const_(f), const_(seq)));
158
159 nullary_fobj_nc nc_f;
160 // ...and we further ensure there is no copying in this case, using a
161 // noncopyable function object.
162 BOOST_TEST(nc_f () == fusion::invoke_function_object<nullary_fobj_nc &>(nc_f , seq ));
163 BOOST_TEST(nc_f () == fusion::invoke_function_object<nullary_fobj_nc &>(nc_f , const_(seq)));
164 BOOST_TEST(const_(nc_f)() == fusion::invoke_function_object<nullary_fobj_nc const &>(const_(nc_f), seq ));
165 BOOST_TEST(const_(nc_f)() == fusion::invoke_function_object<nullary_fobj_nc const &>(const_(nc_f), const_(seq)));
166 }
167
168 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<1>)169 void test_sequence_n(Sequence & seq, mpl::int_<1>)
170 {
171 fobj f;
172 BOOST_TEST(f(element1) == fusion::invoke_function_object(f , seq ));
173 BOOST_TEST(f(element1) == fusion::invoke_function_object(f , const_(seq)));
174 BOOST_TEST(const_(f)(element1) == fusion::invoke_function_object<fobj const >(const_(f), seq ));
175 BOOST_TEST(const_(f)(element1) == fusion::invoke_function_object<fobj const &>(const_(f), const_(seq)));
176
177 fobj_nc nc_f;
178 BOOST_TEST(nc_f(element1) == fusion::invoke_function_object<fobj_nc &>(nc_f, seq ));
179 BOOST_TEST(nc_f(element1) == fusion::invoke_function_object<fobj_nc &>(nc_f, const_(seq)));
180 BOOST_TEST(const_(nc_f)(element1) == fusion::invoke_function_object<fobj_nc const &>(const_(nc_f), seq ));
181 BOOST_TEST(const_(nc_f)(element1) == fusion::invoke_function_object<fobj_nc const &>(const_(nc_f), const_(seq)));
182 }
183
184 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<2>)185 void test_sequence_n(Sequence & seq, mpl::int_<2>)
186 {
187 fobj f;
188 BOOST_TEST(f (element1, element2) == fusion::invoke_function_object(f , seq));
189 BOOST_TEST(f (element1, const_(element2)) == fusion::invoke_function_object(f , const_(seq)));
190 BOOST_TEST(const_(f)(element1, element2) == fusion::invoke_function_object<fobj const>(const_(f), seq));
191 BOOST_TEST(const_(f)(element1, const_(element2)) == fusion::invoke_function_object<fobj const>(const_(f), const_(seq)));
192 }
193
194 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<3>)195 void test_sequence_n(Sequence & seq, mpl::int_<3>)
196 {
197 fobj f;
198
199 BOOST_TEST(f(element1, element2, element3) == fusion::invoke_function_object(f, seq));
200 BOOST_TEST(const_(f)(element1, element2, element3) == fusion::invoke_function_object<fobj const>(const_(f), seq));
201 }
202
203 template <class Sequence>
test_sequence(Sequence & seq)204 void test_sequence(Sequence & seq)
205 {
206 test_sequence_n(seq, mpl::int_<boost::fusion::result_of::size<Sequence>::value>());
207 }
208
result_type_tests()209 void result_type_tests()
210 {
211 using boost::is_same;
212
213 BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< nullary_fobj, fusion::vector<> >::type, int >::value ));
214 BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< fobj, fusion::vector<element1_type> >::type, int >::value ));
215 BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< fobj, fusion::vector<element1_type,element2_type> >::type, int >::value ));
216 }
217
218
main()219 int main()
220 {
221 result_type_tests();
222
223 typedef fusion::vector<> vector0;
224 typedef fusion::vector<element1_type> vector1;
225 typedef fusion::vector<element1_type, element2_type> vector2;
226 typedef fusion::vector<element1_type, element2_type, element3_type> vector3;
227
228 vector0 v0;
229 vector1 v1(element1);
230 vector2 v2(element1, element2);
231
232 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
233 // Note: C++11 will pickup the rvalue overload for the d argument
234 // since we do not have all permutations (expensive!) for all const&
235 // and && arguments. We either have all && or all const& arguments only.
236 // For that matter, use std::ref to disambiguate the call.
237
238 vector3 v3(element1, element2, std::ref(element3));
239 #else
240 vector3 v3(element1, element2, element3);
241 #endif
242
243 test_sequence(v0);
244 test_sequence(v1);
245 test_sequence(v2);
246 test_sequence(v3);
247
248 typedef fusion::list<> list0;
249 typedef fusion::list<element1_type> list1;
250 typedef fusion::list<element1_type, element2_type> list2;
251 typedef fusion::list<element1_type, element2_type, element3_type> list3;
252
253 list0 l0;
254 list1 l1(element1);
255 list2 l2(element1, element2);
256 list3 l3(element1, element2, element3);
257
258 test_sequence(l0);
259 test_sequence(l1);
260 test_sequence(l2);
261 test_sequence(l3);
262
263 return boost::report_errors();
264 }
265
266