apply.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana/assert.hpp>
  5. #include <boost/hana/equal.hpp>
  6. #include <boost/hana/functional/apply.hpp>
  7. #include <laws/base.hpp>
  8. #include <support/tracked.hpp>
  9. #include <type_traits>
  10. #include <utility>
  11. namespace hana = boost::hana;
  12. template <int i = 0>
  13. struct nonpod : Tracked {
  14. nonpod() : Tracked{i} { }
  15. };
  16. struct NonCopyable {
  17. NonCopyable() = default;
  18. NonCopyable(NonCopyable const&) = delete;
  19. NonCopyable& operator=(NonCopyable const&) = delete;
  20. };
  21. struct TestClass {
  22. explicit TestClass(int x) : data(x) { }
  23. TestClass(TestClass const&) = delete;
  24. TestClass& operator=(TestClass const&) = delete;
  25. int& operator()(NonCopyable&&) & { return data; }
  26. int const& operator()(NonCopyable&&) const & { return data; }
  27. int volatile& operator()(NonCopyable&&) volatile & { return data; }
  28. int const volatile& operator()(NonCopyable&&) const volatile & { return data; }
  29. int&& operator()(NonCopyable&&) && { return std::move(data); }
  30. int const&& operator()(NonCopyable&&) const && { return std::move(data); }
  31. int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); }
  32. int const volatile&& operator()(NonCopyable&&) const volatile && { return std::move(data); }
  33. int data;
  34. };
  35. struct DerivedFromTestClass : TestClass {
  36. explicit DerivedFromTestClass(int x) : TestClass(x) { }
  37. };
  38. template <typename Signature, typename Expect, typename Functor>
  39. void test_b12(Functor&& f) {
  40. // Create the callable object.
  41. using ClassFunc = Signature TestClass::*;
  42. ClassFunc func_ptr = &TestClass::operator();
  43. // Create the dummy arg.
  44. NonCopyable arg;
  45. // Check that the deduced return type of invoke is what is expected.
  46. using DeducedReturnType = decltype(
  47. hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg))
  48. );
  49. static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
  50. // Check that result_of_t matches Expect.
  51. using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type;
  52. static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
  53. // Run invoke and check the return value.
  54. DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg));
  55. BOOST_HANA_RUNTIME_CHECK(ret == 42);
  56. }
  57. template <typename Expect, typename Functor>
  58. void test_b34(Functor&& f) {
  59. // Create the callable object.
  60. using ClassFunc = int TestClass::*;
  61. ClassFunc func_ptr = &TestClass::data;
  62. // Check that the deduced return type of invoke is what is expected.
  63. using DeducedReturnType = decltype(
  64. hana::apply(func_ptr, std::forward<Functor>(f))
  65. );
  66. static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
  67. // Check that result_of_t matches Expect.
  68. using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&)>::type;
  69. static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
  70. // Run invoke and check the return value.
  71. DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f));
  72. BOOST_HANA_RUNTIME_CHECK(ret == 42);
  73. }
  74. template <typename Expect, typename Functor>
  75. void test_b5(Functor&& f) {
  76. NonCopyable arg;
  77. // Check that the deduced return type of invoke is what is expected.
  78. using DeducedReturnType = decltype(
  79. hana::apply(std::forward<Functor>(f), std::move(arg))
  80. );
  81. static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
  82. // Check that result_of_t matches Expect.
  83. using ResultOfReturnType = typename std::result_of<Functor&&(NonCopyable&&)>::type;
  84. static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
  85. // Run invoke and check the return value.
  86. DeducedReturnType ret = hana::apply(std::forward<Functor>(f), std::move(arg));
  87. BOOST_HANA_RUNTIME_CHECK(ret == 42);
  88. }
  89. int& foo(NonCopyable&&) {
  90. static int data = 42;
  91. return data;
  92. }
  93. int main() {
  94. // Test normal usage with a function object
  95. {
  96. hana::test::_injection<0> f{};
  97. using hana::test::ct_eq;
  98. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  99. hana::apply(f),
  100. f()
  101. ));
  102. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  103. hana::apply(f, ct_eq<0>{}),
  104. f(ct_eq<0>{})
  105. ));
  106. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  107. hana::apply(f, ct_eq<0>{}, ct_eq<1>{}),
  108. f(ct_eq<0>{}, ct_eq<1>{})
  109. ));
  110. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  111. hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
  112. f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
  113. ));
  114. BOOST_HANA_CONSTANT_CHECK(hana::equal(
  115. hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
  116. f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
  117. ));
  118. // Make sure we can use apply with non-PODs
  119. hana::apply(f, nonpod<>{});
  120. }
  121. // Bullets 1 & 2 in the standard
  122. {
  123. TestClass cl(42);
  124. test_b12<int&(NonCopyable&&) &, int&>(cl);
  125. test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
  126. test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
  127. test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
  128. test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
  129. test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
  130. test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
  131. test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
  132. }
  133. {
  134. DerivedFromTestClass cl(42);
  135. test_b12<int&(NonCopyable&&) &, int&>(cl);
  136. test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
  137. test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
  138. test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
  139. test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
  140. test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
  141. test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
  142. test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
  143. }
  144. {
  145. TestClass cl_obj(42);
  146. TestClass *cl = &cl_obj;
  147. test_b12<int&(NonCopyable&&) &, int&>(cl);
  148. test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
  149. test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
  150. test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
  151. }
  152. {
  153. DerivedFromTestClass cl_obj(42);
  154. DerivedFromTestClass *cl = &cl_obj;
  155. test_b12<int&(NonCopyable&&) &, int&>(cl);
  156. test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
  157. test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
  158. test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
  159. }
  160. // Bullets 3 & 4 in the standard
  161. {
  162. using Fn = TestClass;
  163. Fn cl(42);
  164. test_b34<int&>(cl);
  165. test_b34<int const&>(static_cast<Fn const&>(cl));
  166. test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
  167. test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
  168. test_b34<int&&>(static_cast<Fn &&>(cl));
  169. test_b34<int const&&>(static_cast<Fn const&&>(cl));
  170. test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
  171. test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
  172. }
  173. {
  174. using Fn = DerivedFromTestClass;
  175. Fn cl(42);
  176. test_b34<int&>(cl);
  177. test_b34<int const&>(static_cast<Fn const&>(cl));
  178. test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
  179. test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
  180. test_b34<int&&>(static_cast<Fn &&>(cl));
  181. test_b34<int const&&>(static_cast<Fn const&&>(cl));
  182. test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
  183. test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
  184. }
  185. {
  186. using Fn = TestClass;
  187. Fn cl_obj(42);
  188. Fn* cl = &cl_obj;
  189. test_b34<int&>(cl);
  190. test_b34<int const&>(static_cast<Fn const*>(cl));
  191. test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
  192. test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
  193. }
  194. {
  195. using Fn = DerivedFromTestClass;
  196. Fn cl_obj(42);
  197. Fn* cl = &cl_obj;
  198. test_b34<int&>(cl);
  199. test_b34<int const&>(static_cast<Fn const*>(cl));
  200. test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
  201. test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
  202. }
  203. // Bullet 5 in the standard
  204. using FooType = int&(NonCopyable&&);
  205. {
  206. FooType& fn = foo;
  207. test_b5<int &>(fn);
  208. }
  209. {
  210. FooType* fn = foo;
  211. test_b5<int &>(fn);
  212. }
  213. {
  214. using Fn = TestClass;
  215. Fn cl(42);
  216. test_b5<int&>(cl);
  217. test_b5<int const&>(static_cast<Fn const&>(cl));
  218. test_b5<int volatile&>(static_cast<Fn volatile&>(cl));
  219. test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl));
  220. test_b5<int&&>(static_cast<Fn &&>(cl));
  221. test_b5<int const&&>(static_cast<Fn const&&>(cl));
  222. test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl));
  223. test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
  224. }
  225. }