apply.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*=============================================================================
  2. Copyright (c) 2015 Paul Fultz II
  3. apply.h
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ==============================================================================*/
  7. #ifndef BOOST_HOF_GUARD_APPLY_H
  8. #define BOOST_HOF_GUARD_APPLY_H
  9. /// apply
  10. /// =====
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The `apply` function calls the function given to it with its arguments.
  16. ///
  17. /// Synopsis
  18. /// --------
  19. ///
  20. /// template<class F, class... Ts>
  21. /// constexpr auto apply(F&& f, Ts&&... xs);
  22. ///
  23. /// Semantics
  24. /// ---------
  25. ///
  26. /// assert(apply(f)(xs...) == f(xs...));
  27. /// assert(fold(apply, f)(x, y, z) == f(x)(y)(z));
  28. ///
  29. /// Requirements
  30. /// ------------
  31. ///
  32. /// F must be:
  33. ///
  34. /// * [Invocable](Invocable)
  35. ///
  36. /// Example
  37. /// -------
  38. ///
  39. /// #include <boost/hof.hpp>
  40. /// #include <cassert>
  41. ///
  42. /// struct sum_f
  43. /// {
  44. /// template<class T, class U>
  45. /// T operator()(T x, U y) const
  46. /// {
  47. /// return x+y;
  48. /// }
  49. /// };
  50. ///
  51. /// int main() {
  52. /// assert(boost::hof::apply(sum_f(), 1, 2) == 3);
  53. /// }
  54. ///
  55. #include <boost/hof/detail/result_of.hpp>
  56. #include <boost/hof/detail/forward.hpp>
  57. #include <boost/hof/detail/static_const_var.hpp>
  58. #ifdef _MSC_VER
  59. #pragma warning(push)
  60. #pragma warning(disable: 4003)
  61. #endif
  62. #define BOOST_HOF_DETAIL_FOREACH_QUAL(m, data) \
  63. m(, data) \
  64. m(const, data) \
  65. m(volatile, data) \
  66. m(const volatile, data)
  67. namespace boost { namespace hof {
  68. namespace detail {
  69. #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE
  70. struct apply_mem_fn
  71. {
  72. template<class...>
  73. struct convertible_args;
  74. template<class T, class U, class=void>
  75. struct is_convertible_args
  76. : std::false_type
  77. {};
  78. template<class... Ts, class... Us>
  79. struct is_convertible_args<
  80. convertible_args<Ts...>,
  81. convertible_args<Us...>,
  82. typename std::enable_if<(
  83. sizeof...(Ts) == sizeof...(Us)
  84. )>::type
  85. >
  86. : and_<std::is_convertible<Ts, Us>...>
  87. {};
  88. template<class From, class To>
  89. struct is_compatible
  90. : std::is_convertible<
  91. typename std::add_pointer<typename std::remove_reference<From>::type>::type,
  92. typename std::add_pointer<typename std::remove_reference<To>::type>::type
  93. >
  94. {};
  95. #define BOOST_HOF_APPLY_MEM_FN_CALL(cv, data) \
  96. template <class R, class Base, class Derived, class... Ts, class... Us, class=typename std::enable_if<and_< \
  97. is_compatible<Derived, cv Base>, \
  98. is_convertible_args<convertible_args<Us...>, convertible_args<Ts...>> \
  99. >::value>::type> \
  100. constexpr R operator()(R (Base::*mf)(Ts...) cv, Derived&& ref, Us &&... xs) const \
  101. BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...)) \
  102. { \
  103. return (BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...); \
  104. }
  105. BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_FN_CALL, ~)
  106. };
  107. struct apply_mem_data
  108. {
  109. template<class T, class R>
  110. struct match_qualifier
  111. { typedef R type; };
  112. #define BOOST_HOF_APPLY_MEM_DATA_MATCH(cv, ref) \
  113. template<class T, class R> \
  114. struct match_qualifier<cv T ref, R> \
  115. : match_qualifier<T, cv R ref> \
  116. {};
  117. BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&)
  118. BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&&)
  119. template <class Base, class R, class Derived, class=typename std::enable_if<(
  120. std::is_base_of<Base, typename std::decay<Derived>::type>::value
  121. )>::type>
  122. constexpr typename match_qualifier<Derived, R>::type
  123. operator()(R Base::*pmd, Derived&& ref) const noexcept
  124. {
  125. return BOOST_HOF_FORWARD(Derived)(ref).*pmd;
  126. }
  127. };
  128. template<class T, class U=decltype(*std::declval<T>())>
  129. struct apply_deref
  130. { typedef U type; };
  131. #endif
  132. struct apply_f
  133. {
  134. #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE
  135. template<class F, class T, class... Ts, class=typename std::enable_if<(
  136. std::is_member_function_pointer<typename std::decay<F>::type>::value
  137. )>::type>
  138. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T>, id_<Ts>...)
  139. operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  140. (
  141. apply_mem_fn()(f, BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...)
  142. );
  143. template<class F, class T, class... Ts, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
  144. std::is_member_function_pointer<typename std::decay<F>::type>::value
  145. )>::type>
  146. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<U>, id_<Ts>...)
  147. operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  148. (
  149. apply_mem_fn()(f, *BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...)
  150. );
  151. template<class F, class T, class... Ts, class=typename std::enable_if<(
  152. std::is_member_function_pointer<typename std::decay<F>::type>::value
  153. )>::type>
  154. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T&>, id_<Ts>...)
  155. operator()(F&& f, const std::reference_wrapper<T>& ref, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  156. (
  157. apply_mem_fn()(f, ref.get(), BOOST_HOF_FORWARD(Ts)(xs)...)
  158. );
  159. template<class F, class T, class=typename std::enable_if<(
  160. std::is_member_object_pointer<typename std::decay<F>::type>::value
  161. )>::type>
  162. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T>)
  163. operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  164. (
  165. apply_mem_data()(f, BOOST_HOF_FORWARD(T)(obj))
  166. );
  167. template<class F, class T, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
  168. std::is_member_object_pointer<typename std::decay<F>::type>::value
  169. )>::type>
  170. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<U>)
  171. operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  172. (
  173. apply_mem_data()(f, *BOOST_HOF_FORWARD(T)(obj))
  174. );
  175. template<class F, class T, class=typename std::enable_if<(
  176. std::is_member_object_pointer<typename std::decay<F>::type>::value
  177. )>::type>
  178. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T&>)
  179. operator()(F&& f, const std::reference_wrapper<T>& ref) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  180. (
  181. apply_mem_data()(f, ref.get())
  182. );
  183. #else
  184. template <class Base, class T, class Derived>
  185. constexpr auto operator()(T Base::*pmd, Derived&& ref) const
  186. BOOST_HOF_RETURNS(BOOST_HOF_FORWARD(Derived)(ref).*pmd);
  187. template <class PMD, class Pointer>
  188. constexpr auto operator()(PMD&& pmd, Pointer&& ptr) const
  189. BOOST_HOF_RETURNS((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMD)(pmd));
  190. template <class Base, class T, class Derived>
  191. constexpr auto operator()(T Base::*pmd, const std::reference_wrapper<Derived>& ref) const
  192. BOOST_HOF_RETURNS(ref.get().*pmd);
  193. template <class Base, class T, class Derived, class... Args>
  194. constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const
  195. BOOST_HOF_RETURNS((BOOST_HOF_FORWARD(Derived)(ref).*pmf)(BOOST_HOF_FORWARD(Args)(args)...));
  196. template <class PMF, class Pointer, class... Args>
  197. constexpr auto operator()(PMF&& pmf, Pointer&& ptr, Args&&... args) const
  198. BOOST_HOF_RETURNS(((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMF)(pmf))(BOOST_HOF_FORWARD(Args)(args)...));
  199. template <class Base, class T, class Derived, class... Args>
  200. constexpr auto operator()(T Base::*pmf, const std::reference_wrapper<Derived>& ref, Args&&... args) const
  201. BOOST_HOF_RETURNS((ref.get().*pmf)(BOOST_HOF_FORWARD(Args)(args)...));
  202. #endif
  203. template<class F, class... Ts>
  204. constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(F, id_<Ts>...)
  205. operator()(F&& f, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
  206. (
  207. f(BOOST_HOF_FORWARD(Ts)(xs)...)
  208. );
  209. };
  210. }
  211. BOOST_HOF_DECLARE_STATIC_VAR(apply, detail::apply_f);
  212. }} // namespace boost::hof
  213. #ifdef _MSC_VER
  214. #pragma warning(pop)
  215. #endif
  216. #endif