/* * Copyright 2003 - 2016, The libsigc++ Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SIGC_ADAPTORS_BIND_H #define SIGC_ADAPTORS_BIND_H #include #include #include #include #include #include #include #include namespace sigc { /** @defgroup bind bind(), bind_return() * sigc::bind() alters an arbitrary functor by fixing arguments to certain values. * For single argument binding, overloads of sigc::bind() are provided that let you * specify the zero-based position of the argument to fix with the first template parameter. * (A value of @p -1 fixes the last argument so sigc::bind<-1>() gives the same result as * sigc::bind().) * The types of the arguments can optionally be specified if not deduced. * * @par Examples: * @code * void foo(int, int, int); * // single argument binding ... * sigc::bind(&foo,1)(2,3); //fixes the last (third) argument and calls foo(2,3,1) * sigc::bind<-1>(&foo,1)(2,3); //same as bind(&foo,1)(2,3) (calls foo(2,3,1)) * sigc::bind<0>(&foo,1)(2,3); //fixes the first argument and calls foo(1,2,3) * sigc::bind<1>(&foo,1)(2,3); //fixes the second argument and calls foo(2,1,3) * sigc::bind<2>(&foo,1)(2,3); //fixes the third argument and calls foo(2,3,1) * // multi argument binding ... * sigc::bind(&foo,1,2)(3); //fixes the last two arguments and calls foo(3,1,2) * sigc::bind(&foo,1,2,3)(); //fixes all three arguments and calls foo(1,2,3) * @endcode * * The functor sigc::bind() returns can be passed into * @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" directly. * * @par Example: * @code * sigc::signal some_signal; * void foo(int); * some_signal.connect(sigc::bind(&foo,1)); * @endcode * * sigc::bind_return() alters an arbitrary functor by * fixing its return value to a certain value. * * @par Example: * @code * void foo(); * std::cout << sigc::bind_return(&foo, 5)(); // calls foo() and returns 5 * @endcode * * You can bind references to functors by passing the objects through * the std::ref() helper function. * * @par Example: * @code * int some_int; * sigc::signal some_signal; * void foo(int&); * some_signal.connect(sigc::bind(&foo, std::ref(some_int))); * @endcode * * If you bind an object of a sigc::trackable derived type to a functor * by reference, a slot assigned to the bind adaptor is cleared automatically * when the object goes out of scope. * * @par Example: * @code * struct bar : public sigc::trackable {} some_bar; * sigc::signal some_signal; * void foo(bar&); * some_signal.connect(sigc::bind(&foo, std::ref(some_bar))); * // disconnected automatically if some_bar goes out of scope * @endcode * * @ingroup adaptors */ namespace internal { template struct TransformEachInvoker { // We take T_element as non-const because invoke() is not const. // TODO: Take element as T_element&& ? constexpr static decltype(auto) transform(T_element& element) { return element.invoke(); } }; } // namespace internal /** Adaptor that binds arguments to the wrapped functor. * Use the convenience function sigc::bind() to create an instance of sigc::bind_functor. * * The following template arguments are used: * - @e I_location Zero-based position of the argument to fix (@p -1 for the last argument). * - @e T_bound Types of the bound argument. * - @e T_functor Type of the functor to wrap. * * @ingroup bind */ template struct bind_functor : public adapts { /** Invokes the wrapped functor passing on the arguments. * bound_ is passed as the next argument. * @param arg Arguments to be passed on to the functor. * @return The return value of the functor invocation. */ template decltype(auto) operator()(T_arg&&... arg) { // For instance, if I_location is 1, and arg has 4 arguments, // we would want to call operator() with (arg0, bound, arg1, arg2). using tuple_type_args = std::tuple...>; const auto t_args = std::tuple(std::forward(arg)...); constexpr auto t_args_size = std::tuple_size::value; // Prevent calling tuple_start<> with values that will cause a compilation error. static_assert(I_location <= t_args_size, "I_location must be less than or equal to the number of arguments."); const auto t_start = internal::tuple_start(t_args); const auto t_bound = internal::tuple_transform_each(bound_); const auto t_end = internal::tuple_end(t_args); const auto t_with_bound = std::tuple_cat(t_start, t_bound, t_end); return std::apply(this->functor_, t_with_bound); } /** Constructs a bind_functor object that binds an argument to the passed functor. * @param func Functor to invoke from operator()(). * @param bound Argument to bind to the functor. */ bind_functor(type_trait_take_t func, type_trait_take_t... bound) : adapts(func), bound_(bound...) { } // public to avoid template friend declarations (used by visitor::do_visit_each()) /// The arguments bound to the functor. std::tuple...> bound_; }; /** Adaptor that binds argument(s) to the wrapped functor. * This template specialization fixes the last argument(s) of the wrapped functor. * * @ingroup bind */ template struct bind_functor<-1, T_functor, T_type...> : public adapts { public: /** Invokes the wrapped functor passing on the arguments. * bound_ is passed as the next argument. * @param arg Arguments to be passed on to the functor. * @return The return value of the functor invocation. */ template decltype(auto) operator()(T_arg&&... arg) { // For instance, if arg has 4 arguments, // we would want to call operator() with (arg0, arg1, arg2, bound). const auto t_args = std::tuple(std::forward(arg)...); const auto t_bound = internal::tuple_transform_each(bound_); const auto t_with_bound = std::tuple_cat(t_args, t_bound); return std::apply(this->functor_, t_with_bound); } /** Constructs a bind_functor object that binds an argument to the passed functor. * @param func Functor to invoke from operator()(). * @param bound Arguments to bind to the functor. */ bind_functor(type_trait_take_t func, type_trait_take_t... bound) : adapts(func), bound_(bound...) { } // public to avoid template friend declarations (used by visitor::do_visit_each()) /// The argument bound to the functor. std::tuple...> bound_; }; #ifndef DOXYGEN_SHOULD_SKIP_THIS // template specialization of visitor<>::do_visit_each<>(action, functor): /** Performs a functor on each of the targets of a functor. * The function overload for sigc::bind_functor performs a functor on the * functor and on the object instances stored in the sigc::bind_functor object. * * @ingroup bind */ template struct visitor> { template static void do_visit_each(const T_action& action, const bind_functor& target) { sigc::visit_each(action, target.functor_); sigc::visit_each(action, std::get<0>(target.bound_)); } }; // template specialization of visitor<>::do_visit_each<>(action, functor): /** Performs a functor on each of the targets of a functor. * The function overload for sigc::bind_functor performs a functor on the * functor and on the object instances stored in the sigc::bind_functor object. * * @ingroup bind */ template struct visitor> { template static void do_visit_each(const T_action& action, const bind_functor<-1, T_functor, T_type...>& target) { sigc::visit_each(action, target.functor_); sigc::internal::tuple_for_each(target.bound_, action); } }; #endif // DOXYGEN_SHOULD_SKIP_THIS /** Creates an adaptor of type sigc::bind_functor which binds the passed argument to the passed * functor. * The optional template argument @e I_location specifies the zero-based * position of the argument to be fixed (@p -1 stands for the last argument). * * @param func Functor that should be wrapped. * @param b Arguments to bind to @e func. * @return Adaptor that executes @e func with the bound argument on invocation. * * @ingroup bind */ template inline decltype(auto) bind(const T_functor& func, T_bound... b) { return bind_functor(func, b...); } /** Creates an adaptor of type sigc::bind_functor which fixes the last arguments of the passed * functor. * This function overload fixes the last arguments of @e func. * * @param func Functor that should be wrapped. * @param b Arguments to bind to @e func. * @return Adaptor that executes func with the bound argument on invocation. * * @ingroup bind */ template inline decltype(auto) bind(const T_functor& func, T_type... b) { return bind_functor<-1, T_functor, T_type...>(func, b...); } } /* namespace sigc */ #endif /* SIGC_ADAPTORS_BIND_H */