Is there a way to partially bind the first/last n arguments of a callable object (e.g. function) without explicitly specifying the rest of the arguments?
std::bind()
seems to require that all the arguments are be bound, those that are to be left should be bound to std::placeholders::_1
,_2
,_3
etc.
Is it possible to write a bind_first()
/bind_last()
for partial binding starting from the first/last argument and that automagically inserts the placeholders for any remaining unbound arguments in their original order in their the original position?
Neither Boost nor the standard library bind
fill in the blanks automatically. You could write such a gadget yourself if you have a rainy evening to fill; here's an example for trailing arguments of a plain function only:
#include <tuple>
#include <type_traits>
#include <utility>
template <typename F, typename ...Args> struct trailing_binder;
template <typename R, typename ...Frgs, typename ...Args>
struct trailing_binder<R(Frgs...), Args...>
{
template <typename ...Brgs>
trailing_binder(R (*f)(Frgs...), Brgs &&... brgs)
: the_function(f)
, the_args(std::forward<Brgs>(brgs)...)
{ }
template <unsigned int ...I> struct intlist {};
template <typename ...Brgs>
typename std::enable_if<sizeof...(Brgs) + sizeof...(Args) == sizeof...(Frgs), R>::type
operator()(Brgs &&... brgs)
{
return unwrap(std::integral_constant<bool, 0 == sizeof...(Args)>(),
intlist<>(),
std::forward<Brgs>(brgs)...);
}
private:
template <unsigned int ...I, typename ...Brgs>
R unwrap(std::false_type, intlist<I...>, Brgs &&... brgs)
{
return unwrap(std::integral_constant<bool, sizeof...(I) + 1 == sizeof...(Args)>(),
intlist<I..., sizeof...(I)>(),
std::forward<Brgs>(brgs)...);
}
template <unsigned int ...I, typename ...Brgs>
R unwrap(std::true_type, intlist<I...>, Brgs &&... brgs)
{
return the_function(std::get<I>(the_args)..., std::forward<Brgs>(brgs)...);
}
R (*the_function)(Frgs...);
std::tuple<Args...> the_args;
};
template <typename R, typename ...Args, typename ...Frgs>
trailing_binder<R(Frgs...), Args...> trailing_bind(R (*f)(Frgs...), Args &&... args)
{
return trailing_binder<R(Frgs...), typename std::decay<Args>::type...>(f, std::forward<Args>(args)...);
}
Usage:
int f(int a, int b, int c, int d) { return a + b + c + d; }
int main()
{
auto b = trailing_bind(f, 1);
return b(3, 8, 13);
}
Inspired by the question, I wrote my own prebind from scratch. It ended up looking pretty similar to everyone else though, but I promise it's original :) - call it convergent evolution.
It has a slightly different flavour though. For one thing, it forwards to it's constructor, but you may prefer to use std::decay
(it makes more sense in some ways, but I don't like writing std::ref
everywhere). For another I added support for nested prebinds so prebind(foo, prebind(GetRandomNumber))()
is the same as prebind(foo)(GetRandomNumber())
.
#include <tuple>
#include <type_traits>
using namespace std;
struct pb_tag {}; //use inheritance to mark prebinder structs
//result_of_t will be defined by default in c++1y
template<typename T > using result_of_t = typename result_of<T>::type;
template<typename T> using is_prebinder = is_base_of<pb_tag, typename remove_reference<T>::type >;
//ugly sequence generators for something different
template<int N, int ...S> struct seq : seq<N-1, N, S...> {};
template<int ...S> struct seq<0, S...> {typedef seq type;};
//these three functions are only for nested prebind. they map
//T t -> T t and Prebind<f, T...> -> f(T...)
template<typename T>
auto dispatchee(T&& t, false_type) -> decltype(forward<T>(t)){
return forward<T>(t);
}
template<typename T>
auto dispatchee(T&& t, true_type) -> decltype(t())
{
return t();
}
template<typename T>
auto expand(T&& t) -> decltype(dispatchee(forward<T>(t), is_prebinder<T>()))
{
return dispatchee(forward<T>(t), is_prebinder<T>());
}
template<typename T> using expand_type = decltype(expand(declval<T>()));
//the functor which holds the closure in a tuple
template<typename f, typename ...ltypes>
struct prebinder : public pb_tag
{
tuple<f, ltypes...> closure;
typedef typename seq<sizeof...(ltypes)>::type sequence;
prebinder(f F, ltypes... largs) : closure(F, largs...) {}
template<int ...S, typename ...rtypes>
result_of_t<f(expand_type<ltypes>..., rtypes...)>
apply(seq<0, S...>, rtypes&& ... rargs){
return (get<0>(closure))(expand(get<S>(closure))... , forward<rtypes>(rargs)...);
}
template<typename ...rtypes>
result_of_t<f(expand_type<ltypes>..., rtypes...)>
operator() (rtypes&& ... rargs){
return apply(sequence(), forward<rtypes>(rargs)...);
}
};
template<typename f, typename ...ltypes>
prebinder<f, ltypes...> prebind(f&& F, ltypes&&... largs)
{
return prebinder<f, ltypes...>(forward<f>(F), forward<ltypes>(largs)...);
}
It can be easily changed to postbind as well.
Usage looks like:
int g(int a){ return 1 + a; }
int h(){ return 1; }
int i(int a, int b, int c, int d){
return 1 + a + b + c + d;
}
int main()
{
//completely bound
auto a = prebind(g, 1);
cout << a() << endl;
//nested bind by reference
auto b = prebind(g, a);
cout << b() << endl;
get<1>(a.closure) = 2;
cout << b() << endl;
//bind to prebinder
auto c = prebind(b);
cout << c() << endl;
//nested bind of temp to temp
auto d = prebind(prebind(g), prebind(h));
cout << d() << endl;
//and the one you wanted orginally
auto e = prebind(i, 1, 1, 1);
cout << e(1) << endl;
return 0;
}