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
waterfall
when 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
first
in order correctlystd::bind
it. std::bind
's return type doesn't behave way want: nestingstd::bind
calls 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::function
s. 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::function
s, because makes code way shorter , way clearer large waterfall
s.
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