c++ - std::bind-like function returning a std::function -
i need bind function behaves std::bind, returns appropriate specialization of std::function.
i think std::function template arguments can extracted using placeholder number function's parameter. doesn't trivial though. there implementation available already?
why need this
i want implement waterfall function semantics similar this javascript one.
here how imagine 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 take bunch of functions, each of (but last one) takes function first parameter. waterfall bind every function previous 1 (starting last one, of course), , return single function.
basically waterfall should this:
// recursion termination: `waterfall` called single functions template< typename arg > auto waterfall( const arg& first ) -> decltype( first ) { return first; } // recursion: `waterfall` called mulitple functions template< typename arg, typename... args > ... waterfall( const arg& first, args... args ) { return std::bind( first, waterfall(std::forward<args>(args)...) ); } there 3 open problems though:
- figuring out return type of
waterfallwhen called multiple arguments. cannotdecltype( std::bind(first, waterfall(...)) )(because c++ doesn't allow recursively calling template function deduce type). if knew type of function (i.e.arg), that, without first argument, return type i'm looking for. - i think need know number of arguments of
firstin order correctlystd::bindit. std::bind's return type doesn't behave way want: nestingstd::bindcalls merges bound functions together, rather composing them.
i able bypass third point writing std::bind wrapper wraps bound function object of type t such std::is_bind_expression<t>::value == false.
for first 2 points need find out return type , arguments type of waterfall parameters. trivial if functions std::functions. simple if lambdas, classical functions, or functors single operator(): i'd need use this function_traits. i'd really pass functions bound using std::bind waterfall, without having manually cast them std::functions, because makes code way shorter , way clearer large waterfalls.
any ideas, thoughts or suggestions?
the design here of work within helper class details::waterfall 2-function waterfall style composition done in waterfall_call.
#include <iostream> #include <utility> #include <functional> #include <string.h> namespace details { this more efficient if decayed outside of structure definition, reduce unique types in cases. don't care:
template<class f0, class f1> struct waterfall_call { typename std::decay<f0>::type f0; typename std::decay<f1>::type f1; call f0 passing f1 , args...:
template<class...args> auto operator()(args&&... args)const -> typename std::result_of<f0 const&(f1 const&,args...)>::type { return f0( f1, std::forward<args>(args)... ); } }; the center of algorithm:
struct waterfall { for 2 args, use waterfall_call:
template<class f0, class f1> waterfall_call<f0, f1> operator()( f0&& f0, f1&& f1 )const { return { std::forward<f0>(f0), std::forward<f1>(f1) }; } for >2 args, recurse, 2 arg solution:
template<class f0, class...fs, class i=typename std::result_of<waterfall const&(fs...)>::type > auto operator()( f0&& f0, fs&&... fs )const -> typename std::result_of< waterfall( f0, ) >::type { auto child = (*this)( std::forward<fs>(fs)... ); return (*this)( std::forward<f0>(f0), std::move(child) ); } for 1 arg, forward out decayed version of input arg:
template<class f0> auto operator()(f0&&f0)const ->typename std::decay<f0>::type { return std::forward<f0>(f0); } }; } and waterfall delegates details::waterfall:
template<class...fs> auto waterfall(fs&&... fs ) -> typename std::result_of<details::waterfall(fs...)>::type{ return details::waterfall{}( std::forward<fs>(fs)... ); } the other way (besides struct trick above) of getting around recursive template return type deduction limitations take parameter template type namespace of function, , pass recursive calls. enables adl lookup, can recursively find own function when deducing own return type.
Comments
Post a Comment