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
waterfallwhen 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
firstin order to correctlystd::bindit. std::bind's return type doesn't behave the way I want: nestingstd::bindcalls 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::functions. 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::functions, because that makes my code way shorter and way clearer with large waterfalls.
Any ideas, thoughts or suggestions?