Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / sigc++ / adaptors / bind.h
1 #ifndef _SIGC_ADAPTORS_BIND_H_
2 #define _SIGC_ADAPTORS_BIND_H_
3 #include <sigc++/adaptors/adaptor_trait.h>
4 #include <sigc++/adaptors/bound_argument.h>
5 #include <tuple>
6 #include <sigc++/tuple-utils/tuple_for_each.h>
7 #include <sigc++/tuple-utils/tuple_start.h>
8 #include <sigc++/tuple-utils/tuple_end.h>
9 #include <sigc++/tuple-utils/tuple_transform_each.h>
10
11 namespace sigc {
12
13
14 /** @defgroup bind bind(), bind_return()
15  * sigc::bind() alters an arbitrary functor by fixing arguments to certain values.
16  * Up to 7 arguments can be bound at a time.
17  * For single argument binding, overloads of sigc::bind() are provided that let you
18  * specify the zero-based position of the argument to fix with the first template parameter.
19  * (A value of @p -1 fixes the last argument so sigc::bind<-1>() gives the same result as sigc::bind().)
20  * The types of the arguments can optionally be specified if not deduced.
21  *
22  * @par Examples:
23  * @code
24  * void foo(int, int, int);
25  * // single argument binding ...
26  * sigc::bind(&foo,1)(2,3);     //fixes the last (third) argument and calls foo(2,3,1)
27  * sigc::bind<-1>(&foo,1)(2,3); //same as bind(&foo,1)(2,3) (calls foo(2,3,1))
28  * sigc::bind<0>(&foo,1)(2,3);  //fixes the first argument and calls foo(1,2,3)
29  * sigc::bind<1>(&foo,1)(2,3);  //fixes the second argument and calls foo(2,1,3)
30  * sigc::bind<2>(&foo,1)(2,3);  //fixes the third argument and calls foo(2,3,1)
31  * // multi argument binding ...
32  * sigc::bind(&foo,1,2)(3);     //fixes the last two arguments and calls foo(3,1,2)
33  * sigc::bind(&foo,1,2,3)();    //fixes all three arguments and calls foo(1,2,3)
34  * @endcode
35  *
36  * The functor sigc::bind() returns can be passed into
37  * sigc::signal::connect() directly.
38  *
39  * @par Example:
40  * @code
41  * sigc::signal<void()> some_signal;
42  * void foo(int);
43  * some_signal.connect(sigc::bind(&foo,1));
44  * @endcode
45  *
46  * sigc::bind_return() alters an arbitrary functor by
47  * fixing its return value to a certain value.
48  *
49  * @par Example:
50  * @code
51  * void foo();
52  * std::cout << sigc::bind_return(&foo, 5)(); // calls foo() and returns 5
53  * @endcode
54  *
55  * You can bind references to functors by passing the objects through
56  * the std::ref() helper function.
57  *
58  * @par Example:
59  * @code
60  * int some_int;
61  * sigc::signal<void()> some_signal;
62  * void foo(int&);
63  * some_signal.connect(sigc::bind(&foo, std::ref(some_int)));
64  * @endcode
65  *
66  * If you bind an object of a sigc::trackable derived type to a functor
67  * by reference, a slot assigned to the bind adaptor is cleared automatically
68  * when the object goes out of scope.
69  *
70  * @par Example:
71  * @code
72  * struct bar : public sigc::trackable {} some_bar;
73  * sigc::signal<void()> some_signal;
74  * void foo(bar&);
75  * some_signal.connect(sigc::bind(&foo, std::ref(some_bar)));
76  *   // disconnected automatically if some_bar goes out of scope
77  * @endcode
78  *
79  * @ingroup adaptors
80  */
81
82 namespace internal
83 {
84
85 template <class T_element>
86 struct TransformEachInvoker
87 {
88   //We take T_element as non-const because invoke() is not const.
89   //TODO: Take element as T_element&& ?
90   constexpr
91   static
92   decltype(auto)
93   transform(T_element& element) {
94     return element.invoke();
95   }
96 };
97
98 } //namespace internal
99
100 /** Adaptor that binds arguments to the wrapped functor.
101  * Use the convenience function sigc::bind() to create an instance of sigc::bind_functor.
102  *
103  * The following template arguments are used:
104  * - @e I_location Zero-based position of the argument to fix (@p -1 for the last argument).
105  * - @e T_bound Types of the bound argument.
106  * - @e T_functor Type of the functor to wrap.
107  *
108  * @ingroup bind
109  */
110 template <int I_location, class T_functor, class... T_bound>
111 struct bind_functor : public adapts<T_functor>
112 {
113   using adaptor_type = typename adapts<T_functor>::adaptor_type;
114   using result_type = typename adaptor_type::result_type;
115
116   /** Invokes the wrapped functor passing on the arguments.
117    * bound_ is passed as the next argument.
118    * @param _A_arg Arguments to be passed on to the functor.
119    * @return The return value of the functor invocation.
120    */
121   template <class... T_arg>
122   decltype(auto)
123   operator()(T_arg&&... _A_arg)
124     {
125       //For instance, if I_location is 1, and _A_arg has 4 arguments,
126       //we would want to call operator() with (_A_arg0, bound, _A_arg1, _A_arg2).
127       
128       using tuple_type_args = std::tuple<type_trait_pass_t<T_arg>...>;
129       const auto t_args = std::tuple<T_arg...>(std::forward<T_arg>(_A_arg)...);
130       constexpr auto t_args_size = std::tuple_size<tuple_type_args>::value;
131       
132       //Prevent calling tuple_start<> with values that will cause a compilation error.
133       static_assert(I_location <= t_args_size,
134         "I_location must be less than or equal to the number of arguments.");
135
136       const auto t_start = internal::tuple_start<I_location>(t_args);
137       const auto t_bound = internal::tuple_transform_each<internal::TransformEachInvoker>(bound_);
138       const auto t_end = internal::tuple_end<t_args_size - I_location>(t_args);
139       const auto t_with_bound = std::tuple_cat(t_start, t_bound, t_end);
140
141       constexpr const auto seq = std::make_index_sequence<std::tuple_size<decltype(t_with_bound)>::value>();
142       return call_functor_operator_parentheses(t_with_bound, seq);
143     }
144
145   /** Constructs a bind_functor object that binds an argument to the passed functor.
146    * @param _A_func Functor to invoke from operator()().
147    * @param _A_bound Argument to bind to the functor.
148    */
149   bind_functor(type_trait_take_t<T_functor> _A_func, type_trait_take_t<T_bound>... _A_bound)
150     : adapts<T_functor>(_A_func), bound_(_A_bound...)
151     {}
152
153 private:
154   /// The arguments bound to the functor.
155   std::tuple<bound_argument<T_bound>...> bound_;
156
157   template<class T, std::size_t... Is>
158   decltype(auto)
159   call_functor_operator_parentheses(T&& tuple,
160     std::index_sequence<Is...>)
161   {
162     return (this->functor_)(std::get<Is>(std::forward<T>(tuple))...);
163   }
164 };
165
166
167 /** Adaptor that binds argument(s) to the wrapped functor.
168  * This template specialization fixes the last argument(s) of the wrapped functor.
169  *
170  * @ingroup bind
171  */
172 template <class T_functor, class... T_type>
173 struct bind_functor<-1, T_functor, T_type...> : public adapts<T_functor>
174 {
175   using adaptor_type = typename adapts<T_functor>::adaptor_type;
176   using result_type = typename adaptor_type::result_type;
177
178   /** Invokes the wrapped functor passing on the arguments.
179    * bound_ is passed as the next argument.
180    * @param _A_arg Arguments to be passed on to the functor.
181    * @return The return value of the functor invocation.
182    */
183   template <class... T_arg>
184   decltype(auto)
185   operator()(T_arg&&... _A_arg)
186     {
187       //For instance, if _A_arg has 4 arguments,
188       //we would want to call operator() with (_A_arg0, _A_arg1, _A_arg2, bound).
189       
190       const auto t_args = std::tuple<T_arg...>(std::forward<T_arg>(_A_arg)...);
191       const auto t_bound = internal::tuple_transform_each<internal::TransformEachInvoker>(bound_);
192       const auto t_with_bound = std::tuple_cat(t_args, t_bound);
193
194       constexpr auto seq = std::make_index_sequence<std::tuple_size<decltype(t_with_bound)>::value>();
195       return call_functor_operator_parentheses(t_with_bound, seq);
196     }
197
198   /** Constructs a bind_functor object that binds an argument to the passed functor.
199    * @param _A_func Functor to invoke from operator()().
200    * @param _A_bound Arguments to bind to the functor.
201    */
202   bind_functor(type_trait_take_t<T_functor> _A_func, type_trait_take_t<T_type>... _A_bound)
203     : adapts<T_functor>(_A_func), bound_(_A_bound...)
204     {}
205
206   /// The argument bound to the functor.
207   std::tuple<bound_argument<T_type>...> bound_;
208
209 private:
210   template<class T, std::size_t... Is>
211   decltype(auto)
212   call_functor_operator_parentheses(T&& tuple,
213     std::index_sequence<Is...>)
214   {
215     return (this->functor_)(std::get<Is>(std::forward<T>(tuple))...);
216   }
217 };
218
219
220 namespace {
221
222 //TODO: Avoid duplication with TrackObjVisitForEach in track_obj.h
223 template<typename T_element>
224 struct TupleVisitorVisitEach
225 {
226   template<typename T_action>
227   constexpr
228   static
229   void
230   visit(const T_element& element, const T_action& action)
231   {
232     sigc::visit_each(action, element);
233   }
234 };
235
236 } //anonymous namespace
237
238 #ifndef DOXYGEN_SHOULD_SKIP_THIS
239 //template specialization of visitor<>::do_visit_each<>(action, functor):
240 /** Performs a functor on each of the targets of a functor.
241  * The function overload for sigc::bind_functor performs a functor on the
242  * functor and on the object instances stored in the sigc::bind_functor object.
243  *
244  * @ingroup bind
245  */
246 template <int T_loc, class T_functor, class... T_bound>
247 struct visitor<bind_functor<T_loc, T_functor, T_bound...> >
248 {
249   template <class T_action>
250   static void do_visit_each(const T_action& _A_action,
251                             const bind_functor<T_loc, T_functor, T_bound...>& _A_target)
252   {
253     sigc::visit_each(_A_action, _A_target.functor_);
254     sigc::visit_each(_A_action, std::get<0>(_A_target.bound_));
255   }
256 };
257
258 //template specialization of visitor<>::do_visit_each<>(action, functor):
259 /** Performs a functor on each of the targets of a functor.
260  * The function overload for sigc::bind_functor performs a functor on the
261  * functor and on the object instances stored in the sigc::bind_functor object.
262  *
263  * @ingroup bind
264  */
265 template <class T_functor, class... T_type>
266 struct visitor<bind_functor<-1, T_functor, T_type...> >
267 {
268   template <typename T_action>
269   static void do_visit_each(const T_action& _A_action,
270                             const bind_functor<-1, T_functor, T_type...>& _A_target)
271   {
272     sigc::visit_each(_A_action, _A_target.functor_);
273
274     sigc::internal::tuple_for_each<TupleVisitorVisitEach>(_A_target.bound_, _A_action);
275   }
276 };
277
278 #endif // DOXYGEN_SHOULD_SKIP_THIS
279
280 /** Creates an adaptor of type sigc::bind_functor which binds the passed argument to the passed functor.
281  * The optional template argument @e I_location specifies the zero-based
282  * position of the argument to be fixed (@p -1 stands for the last argument).
283  *
284  * @param _A_func Functor that should be wrapped.
285  * @param _A_b1 Argument to bind to @e _A_func.
286  * @return Adaptor that executes @e _A_func with the bound argument on invokation.
287  *
288  * @ingroup bind
289  */
290 template <int I_location, class T_functor, class... T_bound>
291 inline decltype(auto)
292 bind(const T_functor& _A_func, T_bound... _A_b)
293 {
294   return bind_functor<I_location, T_functor, T_bound...>
295            (_A_func, _A_b...);
296 }
297
298 /** Creates an adaptor of type sigc::bind_functor which fixes the last arguments of the passed functor.
299  * This function overload fixes the last arguments of @e _A_func.
300  *
301  * @param _A_func Functor that should be wrapped.
302  * @param _A_b Arguments to bind to @e _A_func.
303  * @return Adaptor that executes _A_func with the bound argument on invokation.
304  *
305  * @ingroup bind
306  */
307 template <class T_functor, class... T_type>
308 inline decltype(auto)
309 bind(const T_functor& _A_func, T_type... _A_b)
310 { return bind_functor<-1, T_functor, T_type...>(_A_func, _A_b...);
311 }
312
313
314 } /* namespace sigc */
315
316 #endif /* _SIGC_ADAPTORS_BIND_H_ */