I need a bind
function that behaves like std::bind
, but returns an appropriate specialization of std::function
.
I think the std::function
template arguments can be extracted using the placeholder number from the function's parameter. This doesn't look that trivial though. Is there any implementation available already?
Why I need this
I want to implement a waterfall
function with a semantics similar to this JavaScript one.
Here is how I imagine it would look like in C++:
std::function<void(const std::string &)> f = waterfall(
[]( const std::function<void(int)> &cb, const std::string & ) {
...;
cb( 1 );
},
[]( const std::function<void(double, double)> &cb, int ) {
...;
cb(0.5, 10);
},
[]( double, double ) {
}
);
In other words, waterfall
would take a bunch of functions, each of which (but the last one) takes a function as the first parameter. waterfall
will bind every function to the previous one (starting from the last one, of course), and return a single function.
Basically waterfall should be something like this:
// recursion termination: `waterfall` called with a single functions
template< typename Arg >
auto waterfall( const Arg& first ) -> decltype( first ) {
return first;
}
// recursion: `waterfall` called with mulitple functions
template< typename Arg, typename... Args >
... waterfall( const Arg& first, Args... args ) {
return std::bind( first, waterfall(std::forward<Args>(args)...) );
}
There are three open problems though:
- Figuring out the return type of
waterfall
when called with multiple arguments. It cannot bedecltype( std::bind(first, waterfall(...)) )
(because C++ doesn't allow recursively calling a template function to deduce its type). If I knew the type of the function (i.e.Arg
), that, without the first argument, would be the return type I'm looking for. - I think I need to know the number of arguments of
first
in order to correctlystd::bind
it. std::bind
's return type doesn't behave the way I want: nestingstd::bind
calls merges all the bound functions together, rather than composing them.
I was able to bypass the third point by writing an std::bind
wrapper that wraps the bound function into an object of a type T
such that std::is_bind_expression<T>::value == false
.
For the first two points I need to find out the return type and the arguments type of waterfall
parameters. This would be trivial if the functions were std::function
s. It would also be simple if they are lambdas, classical functions, or functors with a single operator()
: I'd just need to use something like this function_traits
. However I'd really like to pass functions bound using std::bind
to waterfall
, without having to manually cast them into std::function
s, because that makes my code way shorter and way clearer with large waterfall
s.
Any ideas, thoughts or suggestions?