invoke_function_object.cpp 9.5 KB

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