You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bind_back.hpp 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 RANGE_V3_DETAIL_BIND_BACK_HPP
  14. #define RANGE_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. namespace ranges
  21. {
  22. // bind_back like std::bind_front has no special treatment for nested
  23. // bind-expressions or reference_wrappers; there is no need to wrap
  24. // Callables with ranges::protect.
  25. namespace detail
  26. {
  27. template<typename Fn, typename... Args>
  28. struct bind_back_fn_
  29. {
  30. using tuple_t = std::tuple<Fn, Args...>;
  31. tuple_t fn_args_;
  32. template<typename... CallArgs>
  33. constexpr auto operator()(CallArgs &&... cargs) &&
  34. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Args...>)
  35. -> invoke_result_t<Fn, CallArgs..., Args...>
  36. {
  37. return tuple_apply(
  38. [&](auto && fn, auto &&... args) -> decltype(auto) {
  39. return invoke((decltype(fn))fn,
  40. (CallArgs &&) cargs...,
  41. (decltype(args))args...);
  42. },
  43. (std::tuple<Fn, Args...> &&) fn_args_);
  44. }
  45. /// \overload
  46. template<typename... CallArgs>
  47. constexpr auto operator()(CallArgs &&... cargs) &
  48. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Args &...>)
  49. -> invoke_result_t<Fn &, CallArgs..., Args &...>
  50. {
  51. return tuple_apply(
  52. [&](auto & fn, auto &... args) -> decltype(auto) {
  53. return invoke(fn, (CallArgs &&) cargs..., args...);
  54. },
  55. fn_args_);
  56. }
  57. /// \overload
  58. template<typename... CallArgs>
  59. constexpr auto operator()(CallArgs &&... cargs) const & noexcept(
  60. is_nothrow_invocable_v<Fn const &, CallArgs..., Args const &...>)
  61. -> invoke_result_t<Fn const &, CallArgs..., Args const &...>
  62. {
  63. return tuple_apply(
  64. [&](auto & fn, auto &... args) -> decltype(auto) {
  65. return invoke(fn, (CallArgs &&) cargs..., args...);
  66. },
  67. fn_args_);
  68. }
  69. };
  70. /// \cond
  71. // Unroll a few instantiations to avoid a heavy-weight tuple instantiation
  72. template<typename Fn, typename Arg>
  73. struct bind_back_fn_<Fn, Arg>
  74. {
  75. struct tuple_t
  76. {
  77. Fn fn_;
  78. Arg arg_;
  79. };
  80. tuple_t fn_args_;
  81. template<typename... CallArgs>
  82. constexpr auto operator()(CallArgs &&... cargs) &&
  83. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg>)
  84. -> invoke_result_t<Fn, CallArgs..., Arg>
  85. {
  86. return invoke(
  87. (Fn &&) fn_args_.fn_, (CallArgs &&) cargs..., (Arg &&) fn_args_.arg_);
  88. }
  89. template<typename... CallArgs>
  90. constexpr auto operator()(CallArgs &&... cargs) &
  91. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg &>)
  92. -> invoke_result_t<Fn &, CallArgs..., Arg &>
  93. {
  94. return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
  95. }
  96. template<typename... CallArgs>
  97. constexpr auto operator()(CallArgs &&... cargs) const & noexcept(
  98. is_nothrow_invocable_v<Fn const &, CallArgs..., Arg const &>)
  99. -> invoke_result_t<Fn const &, CallArgs..., Arg const &>
  100. {
  101. return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
  102. }
  103. };
  104. template<typename Fn, typename Arg0, typename Arg1>
  105. struct bind_back_fn_<Fn, Arg0, Arg1>
  106. {
  107. struct tuple_t
  108. {
  109. Fn fn_;
  110. Arg0 arg0_;
  111. Arg1 arg1_;
  112. };
  113. tuple_t fn_args_;
  114. template<typename... CallArgs>
  115. constexpr auto operator()(CallArgs &&... cargs) &&
  116. noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg0, Arg1>)
  117. -> invoke_result_t<Fn, CallArgs..., Arg0, Arg1>
  118. {
  119. return invoke((Fn &&) fn_args_.fn_,
  120. (CallArgs &&) cargs...,
  121. (Arg0 &&) fn_args_.arg0_,
  122. (Arg1 &&) fn_args_.arg1_);
  123. }
  124. template<typename... CallArgs>
  125. constexpr auto operator()(CallArgs &&... cargs) &
  126. noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg0 &, Arg1 &>)
  127. -> invoke_result_t<Fn &, CallArgs..., Arg0 &, Arg1 &>
  128. {
  129. return invoke(
  130. fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
  131. }
  132. template<typename... CallArgs>
  133. constexpr auto operator()(CallArgs &&... cargs) const & noexcept(
  134. is_nothrow_invocable_v<Fn const &, CallArgs..., Arg0 const &,
  135. Arg1 const &>)
  136. -> invoke_result_t<Fn const &, CallArgs..., Arg0 const &, Arg1 const &>
  137. {
  138. return invoke(
  139. fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
  140. }
  141. };
  142. /// \endcond
  143. template<typename Fn, typename... Args>
  144. using bind_back_fn = bind_back_fn_<decay_t<Fn>, decay_t<Args>...>;
  145. } // namespace detail
  146. struct bind_back_fn
  147. {
  148. template<typename Fn, typename Arg1, typename... Args>
  149. constexpr auto operator()(Fn && fn, Arg1 && arg1, Args &&... args) const
  150. -> detail::bind_back_fn<Fn, Arg1, Args...>
  151. {
  152. #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
  153. using T = typename detail::bind_back_fn<Fn, Arg1, Args...>::tuple_t;
  154. return {T{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
  155. #else
  156. return {{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
  157. #endif
  158. }
  159. };
  160. /// \ingroup group-utility
  161. /// \sa `bind_back_fn`
  162. RANGES_INLINE_VARIABLE(bind_back_fn, bind_back)
  163. } // namespace ranges
  164. #endif // RANGE_V3_DETAIL_BIND_BACK_HPP