/* 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, see .
*/
#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 that sigc::bind() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @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 */