bind_back.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Andrey Diduh 2019
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_DETAIL_BIND_BACK_HPP
  14. #define RANGES_V3_DETAIL_BIND_BACK_HPP
  15. #include <tuple>
  16. #include <meta/meta.hpp>
  17. #include <range/v3/range_fwd.hpp>
  18. #include <range/v3/functional/invoke.hpp>
  19. #include <range/v3/utility/tuple_algorithm.hpp>
  20. #include <range/v3/detail/prologue.hpp>
  21. namespace ranges
  22. {
  23. // bind_back like std::bind_front has no special treatment for nested
  24. // bind-expressions or reference_wrappers; there is no need to wrap
  25. // Callables with ranges::protect.
  26. namespace detail
  27. {
  28. template<typename Fn, typename... Args>
  29. struct bind_back_fn_
  30. {
  31. using tuple_t = std::tuple<Fn, Args...>;
  32. tuple_t fn_args_;
  33. template<typename... CallArgs>
  34. constexpr invoke_result_t<Fn, CallArgs..., Args...> //
  35. operator()(CallArgs &&... cargs) &&
  36. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Args...>)
  37. {
  38. return tuple_apply(
  39. [&](auto && fn, auto &&... args) -> decltype(auto) {
  40. return invoke((decltype(fn))fn,
  41. (CallArgs &&) cargs...,
  42. (decltype(args))args...);
  43. },
  44. (std::tuple<Fn, Args...> &&) fn_args_);
  45. }
  46. /// \overload
  47. template<typename... CallArgs>
  48. constexpr invoke_result_t<Fn &, CallArgs..., Args &...>
  49. operator()(CallArgs &&... cargs) &
  50. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Args &...>)
  51. {
  52. return tuple_apply(
  53. [&](auto & fn, auto &... args) -> decltype(auto) {
  54. return invoke(fn, (CallArgs &&) cargs..., args...);
  55. },
  56. fn_args_);
  57. }
  58. /// \overload
  59. template<typename... CallArgs>
  60. constexpr invoke_result_t<Fn const &, CallArgs..., Args const &...>
  61. operator()(CallArgs &&... cargs) const & //
  62. noexcept(is_nothrow_invocable_v<Fn const &, CallArgs..., Args const &...>)
  63. {
  64. return tuple_apply(
  65. [&](auto & fn, auto &... args) -> decltype(auto) {
  66. return invoke(fn, (CallArgs &&) cargs..., args...);
  67. },
  68. fn_args_);
  69. }
  70. };
  71. /// \cond
  72. // Unroll a few instantiations to avoid a heavy-weight tuple instantiation
  73. template<typename Fn, typename Arg>
  74. struct bind_back_fn_<Fn, Arg>
  75. {
  76. struct tuple_t
  77. {
  78. Fn fn_;
  79. Arg arg_;
  80. };
  81. tuple_t fn_args_;
  82. template<typename... CallArgs>
  83. constexpr invoke_result_t<Fn, CallArgs..., Arg> //
  84. operator()(CallArgs &&... cargs) && //
  85. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg>)
  86. {
  87. return invoke(
  88. (Fn &&) fn_args_.fn_, (CallArgs &&) cargs..., (Arg &&) fn_args_.arg_);
  89. }
  90. template<typename... CallArgs>
  91. constexpr invoke_result_t<Fn &, CallArgs..., Arg &> //
  92. operator()(CallArgs &&... cargs) & //
  93. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg &>)
  94. {
  95. return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
  96. }
  97. template<typename... CallArgs>
  98. constexpr invoke_result_t<Fn const &, CallArgs..., Arg const &> //
  99. operator()(CallArgs &&... cargs) const & //
  100. noexcept(is_nothrow_invocable_v<Fn const &, CallArgs..., Arg const &>)
  101. {
  102. return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
  103. }
  104. };
  105. template<typename Fn, typename Arg0, typename Arg1>
  106. struct bind_back_fn_<Fn, Arg0, Arg1>
  107. {
  108. struct tuple_t
  109. {
  110. Fn fn_;
  111. Arg0 arg0_;
  112. Arg1 arg1_;
  113. };
  114. tuple_t fn_args_;
  115. template<typename... CallArgs>
  116. constexpr invoke_result_t<Fn, CallArgs..., Arg0, Arg1> //
  117. operator()(CallArgs &&... cargs) && //
  118. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg0, Arg1>)
  119. {
  120. return invoke((Fn &&) fn_args_.fn_,
  121. (CallArgs &&) cargs...,
  122. (Arg0 &&) fn_args_.arg0_,
  123. (Arg1 &&) fn_args_.arg1_);
  124. }
  125. template<typename... CallArgs>
  126. constexpr invoke_result_t<Fn &, CallArgs..., Arg0 &, Arg1 &> //
  127. operator()(CallArgs &&... cargs) & //
  128. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg0 &, Arg1 &>)
  129. {
  130. return invoke(
  131. fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
  132. }
  133. template<typename... CallArgs>
  134. constexpr invoke_result_t<Fn const &, CallArgs..., Arg0 const &, Arg1 const &>
  135. operator()(CallArgs &&... cargs) const &
  136. noexcept(is_nothrow_invocable_v<Fn const &,
  137. CallArgs...,
  138. Arg0 const &,
  139. Arg1 const &>)
  140. {
  141. return invoke(
  142. fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
  143. }
  144. };
  145. /// \endcond
  146. template<typename Fn, typename... Args>
  147. using bind_back_fn = bind_back_fn_<decay_t<Fn>, decay_t<Args>...>;
  148. } // namespace detail
  149. struct bind_back_fn
  150. {
  151. template<typename Fn, typename Arg1, typename... Args>
  152. constexpr detail::bind_back_fn<Fn, Arg1, Args...> //
  153. operator()(Fn && fn, Arg1 && arg1, Args &&... args) const
  154. {
  155. #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
  156. using T = typename detail::bind_back_fn<Fn, Arg1, Args...>::tuple_t;
  157. return {T{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
  158. #else
  159. return {{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
  160. #endif
  161. }
  162. };
  163. /// \ingroup group-utility
  164. /// \sa `bind_back_fn`
  165. RANGES_INLINE_VARIABLE(bind_back_fn, bind_back)
  166. } // namespace ranges
  167. #include <range/v3/detail/epilogue.hpp>
  168. #endif // RANGES_V3_DETAIL_BIND_BACK_HPP