Horizon
bind_back.hpp
Go to the documentation of this file.
1 // 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 
14 #ifndef RANGES_V3_DETAIL_BIND_BACK_HPP
15 #define RANGES_V3_DETAIL_BIND_BACK_HPP
16 
17 #include <tuple>
18 
19 #include <meta/meta.hpp>
20 
21 #include <range/v3/range_fwd.hpp>
22 
25 
26 #include <range/v3/detail/prologue.hpp>
27 
28 namespace ranges
29 {
30  // bind_back like std::bind_front has no special treatment for nested
31  // bind-expressions or reference_wrappers; there is no need to wrap
32  // Callables with ranges::protect.
33  namespace detail
34  {
35  template<typename Fn, typename... Args>
37  {
38  using tuple_t = std::tuple<Fn, Args...>;
39  tuple_t fn_args_;
40 
41  template<typename... CallArgs>
42  constexpr invoke_result_t<Fn, CallArgs..., Args...> //
43  operator()(CallArgs &&... cargs) &&
44  noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Args...>)
45  {
46  return tuple_apply(
47  [&](auto && fn, auto &&... args) -> decltype(auto) {
48  return invoke((decltype(fn))fn,
49  (CallArgs &&) cargs...,
50  (decltype(args))args...);
51  },
52  (std::tuple<Fn, Args...> &&) fn_args_);
53  }
54 
56  template<typename... CallArgs>
57  constexpr invoke_result_t<Fn &, CallArgs..., Args &...>
58  operator()(CallArgs &&... cargs) &
59  noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Args &...>)
60  {
61  return tuple_apply(
62  [&](auto & fn, auto &... args) -> decltype(auto) {
63  return invoke(fn, (CallArgs &&) cargs..., args...);
64  },
65  fn_args_);
66  }
67 
69  template<typename... CallArgs>
70  constexpr invoke_result_t<Fn const &, CallArgs..., Args const &...>
71  operator()(CallArgs &&... cargs) const & //
72  noexcept(is_nothrow_invocable_v<Fn const &, CallArgs..., Args const &...>)
73  {
74  return tuple_apply(
75  [&](auto & fn, auto &... args) -> decltype(auto) {
76  return invoke(fn, (CallArgs &&) cargs..., args...);
77  },
78  fn_args_);
79  }
80  };
81 
83  // Unroll a few instantiations to avoid a heavy-weight tuple instantiation
84  template<typename Fn, typename Arg>
85  struct bind_back_fn_<Fn, Arg>
86  {
87  struct tuple_t
88  {
89  Fn fn_;
90  Arg arg_;
91  };
92  tuple_t fn_args_;
93 
94  template<typename... CallArgs>
95  constexpr invoke_result_t<Fn, CallArgs..., Arg> //
96  operator()(CallArgs &&... cargs) && //
97  noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg>)
98  {
99  return invoke(
100  (Fn &&) fn_args_.fn_, (CallArgs &&) cargs..., (Arg &&) fn_args_.arg_);
101  }
102 
103  template<typename... CallArgs>
104  constexpr invoke_result_t<Fn &, CallArgs..., Arg &> //
105  operator()(CallArgs &&... cargs) & //
106  noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg &>)
107  {
108  return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
109  }
110 
111  template<typename... CallArgs>
112  constexpr invoke_result_t<Fn const &, CallArgs..., Arg const &> //
113  operator()(CallArgs &&... cargs) const & //
114  noexcept(is_nothrow_invocable_v<Fn const &, CallArgs..., Arg const &>)
115  {
116  return invoke(fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg_);
117  }
118  };
119 
120  template<typename Fn, typename Arg0, typename Arg1>
121  struct bind_back_fn_<Fn, Arg0, Arg1>
122  {
123  struct tuple_t
124  {
125  Fn fn_;
126  Arg0 arg0_;
127  Arg1 arg1_;
128  };
129  tuple_t fn_args_;
130 
131  template<typename... CallArgs>
132  constexpr invoke_result_t<Fn, CallArgs..., Arg0, Arg1> //
133  operator()(CallArgs &&... cargs) && //
134  noexcept(is_nothrow_invocable_v<Fn, CallArgs..., Arg0, Arg1>)
135  {
136  return invoke((Fn &&) fn_args_.fn_,
137  (CallArgs &&) cargs...,
138  (Arg0 &&) fn_args_.arg0_,
139  (Arg1 &&) fn_args_.arg1_);
140  }
141 
142  template<typename... CallArgs>
143  constexpr invoke_result_t<Fn &, CallArgs..., Arg0 &, Arg1 &> //
144  operator()(CallArgs &&... cargs) & //
145  noexcept(is_nothrow_invocable_v<Fn &, CallArgs..., Arg0 &, Arg1 &>)
146  {
147  return invoke(
148  fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
149  }
150 
151  template<typename... CallArgs>
152  constexpr invoke_result_t<Fn const &, CallArgs..., Arg0 const &, Arg1 const &>
153  operator()(CallArgs &&... cargs) const &
154  noexcept(is_nothrow_invocable_v<Fn const &,
155  CallArgs...,
156  Arg0 const &,
157  Arg1 const &>)
158  {
159  return invoke(
160  fn_args_.fn_, (CallArgs &&) cargs..., fn_args_.arg0_, fn_args_.arg1_);
161  }
162  };
164 
165  template<typename Fn, typename... Args>
166  using bind_back_fn = bind_back_fn_<decay_t<Fn>, decay_t<Args>...>;
167  } // namespace detail
168 
170  {
171  template<typename Fn, typename Arg1, typename... Args>
172  constexpr detail::bind_back_fn<Fn, Arg1, Args...> //
173  operator()(Fn && fn, Arg1 && arg1, Args &&... args) const
174  {
175 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
176  using T = typename detail::bind_back_fn<Fn, Arg1, Args...>::tuple_t;
177  return {T{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
178 #else
179  return {{(Fn &&) fn, (Arg1 &&) arg1, (Args &&) args...}};
180 #endif
181  }
182  };
183 
187 
188 } // namespace ranges
189 
190 #include <range/v3/detail/epilogue.hpp>
191 
192 #endif // RANGES_V3_DETAIL_BIND_BACK_HPP
RANGES_INLINE_VARIABLE(detail::to_container_fn< detail::from_range< std::vector >>, to_vector) template< template< typename... > class ContT > auto to(RANGES_HIDDEN_DETAIL(detail
For initializing a container of the specified type with the elements of an Range.
Definition: conversion.hpp:399
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
defer< bind_back, Fn, Ts... > bind_back
Definition: meta.hpp:994
Tiny meta-programming library.
Definition: bind_back.hpp:170
Definition: bind_back.hpp:37
constexpr invoke_result_t< Fn const &, CallArgs..., Args const &... > operator()(CallArgs &&... cargs) const &noexcept(is_nothrow_invocable_v< Fn const &, CallArgs..., Args const &... >)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: bind_back.hpp:71
constexpr invoke_result_t< Fn &, CallArgs..., Args &... > operator()(CallArgs &&... cargs) &noexcept(is_nothrow_invocable_v< Fn &, CallArgs..., Args &... >)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: bind_back.hpp:58