apply_eval.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*=============================================================================
  2. Copyright (c) 2015 Paul Fultz II
  3. apply_eval.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_EVAL_H
  8. #define BOOST_HOF_GUARD_APPLY_EVAL_H
  9. /// apply_eval
  10. /// ==========
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The `apply_eval` function work like [`apply`](/include/boost/hof/apply), except it calls
  16. /// [`eval`](/include/boost/hof/eval) on each of its arguments. Each [`eval`](/include/boost/hof/eval) call is
  17. /// always ordered from left-to-right.
  18. ///
  19. /// Synopsis
  20. /// --------
  21. ///
  22. /// template<class F, class... Ts>
  23. /// constexpr auto apply_eval(F&& f, Ts&&... xs);
  24. ///
  25. /// Semantics
  26. /// ---------
  27. ///
  28. /// assert(apply_eval(f)(xs...) == f(eval(xs)...));
  29. ///
  30. /// Requirements
  31. /// ------------
  32. ///
  33. /// F must be:
  34. ///
  35. /// * [ConstInvocable](ConstInvocable)
  36. ///
  37. /// Ts must be:
  38. ///
  39. /// * [EvaluatableFunctionObject](EvaluatableFunctionObject)
  40. ///
  41. /// Example
  42. /// -------
  43. ///
  44. /// #include <boost/hof.hpp>
  45. /// #include <cassert>
  46. ///
  47. /// struct sum_f
  48. /// {
  49. /// template<class T, class U>
  50. /// T operator()(T x, U y) const
  51. /// {
  52. /// return x+y;
  53. /// }
  54. /// };
  55. ///
  56. /// int main() {
  57. /// assert(boost::hof::apply_eval(sum_f(), []{ return 1; }, []{ return 2; }) == 3);
  58. /// }
  59. ///
  60. #include <boost/hof/config.hpp>
  61. #include <boost/hof/returns.hpp>
  62. #include <boost/hof/detail/forward.hpp>
  63. #include <boost/hof/detail/static_const_var.hpp>
  64. #include <boost/hof/apply.hpp>
  65. #include <boost/hof/eval.hpp>
  66. #if BOOST_HOF_NO_ORDERED_BRACE_INIT
  67. #include <boost/hof/pack.hpp>
  68. #include <boost/hof/capture.hpp>
  69. #endif
  70. namespace boost { namespace hof {
  71. namespace detail {
  72. #if BOOST_HOF_NO_ORDERED_BRACE_INIT
  73. template<class R, class F, class Pack>
  74. constexpr R eval_ordered(const F& f, Pack&& p)
  75. {
  76. return p(f);
  77. }
  78. template<class R, class F, class Pack, class T, class... Ts>
  79. constexpr R eval_ordered(const F& f, Pack&& p, T&& x, Ts&&... xs)
  80. {
  81. return boost::hof::detail::eval_ordered<R>(f, boost::hof::pack_join(BOOST_HOF_FORWARD(Pack)(p), boost::hof::pack_forward(boost::hof::eval(x))), BOOST_HOF_FORWARD(Ts)(xs)...);
  82. }
  83. #else
  84. template<class R>
  85. struct eval_helper
  86. {
  87. R result;
  88. template<class F, class... Ts>
  89. constexpr eval_helper(const F& f, Ts&&... xs) : result(boost::hof::apply(f, BOOST_HOF_FORWARD(Ts)(xs)...))
  90. {}
  91. };
  92. template<>
  93. struct eval_helper<void>
  94. {
  95. int x;
  96. template<class F, class... Ts>
  97. constexpr eval_helper(const F& f, Ts&&... xs) : x((boost::hof::apply(f, BOOST_HOF_FORWARD(Ts)(xs)...), 0))
  98. {}
  99. };
  100. #endif
  101. struct apply_eval_f
  102. {
  103. template<class F, class... Ts, class R=decltype(
  104. boost::hof::apply(std::declval<const F&>(), boost::hof::eval(std::declval<Ts>())...)
  105. ),
  106. class=typename std::enable_if<(!std::is_void<R>::value)>::type
  107. >
  108. constexpr R operator()(const F& f, Ts&&... xs) const BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(boost::hof::apply(f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...))
  109. {
  110. return
  111. #if BOOST_HOF_NO_ORDERED_BRACE_INIT
  112. boost::hof::detail::eval_ordered<R>
  113. (f, boost::hof::pack(), BOOST_HOF_FORWARD(Ts)(xs)...);
  114. #else
  115. boost::hof::detail::eval_helper<R>
  116. {f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...}.result;
  117. #endif
  118. }
  119. template<class F, class... Ts, class R=decltype(
  120. boost::hof::apply(std::declval<const F&>(), boost::hof::eval(std::declval<Ts>())...)
  121. ),
  122. class=typename std::enable_if<(std::is_void<R>::value)>::type
  123. >
  124. constexpr typename detail::holder<Ts...>::type
  125. operator()(const F& f, Ts&&... xs) const BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(boost::hof::apply(f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...))
  126. {
  127. return (typename detail::holder<Ts...>::type)
  128. #if BOOST_HOF_NO_ORDERED_BRACE_INIT
  129. boost::hof::detail::eval_ordered<R>
  130. (f, boost::hof::pack(), BOOST_HOF_FORWARD(Ts)(xs)...);
  131. #else
  132. boost::hof::detail::eval_helper<R>
  133. {f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...};
  134. #endif
  135. }
  136. };
  137. }
  138. BOOST_HOF_DECLARE_STATIC_VAR(apply_eval, detail::apply_eval_f);
  139. }} // namespace boost::hof
  140. #endif