All programming problems can be solved with another layer of indirection, with the exception of too many layers of indirection.
My goal is to create a recursive<void(int)> that will allow you to easily create a recursive lambda. To do this, you pass a lambda with the signature void(recursive<void(int)>, int) - the first argument is what you call to make the recursive call.
Then I will bind it in the nodes and make it a fully recursive function with the signature void(int) .
Here is my recursive<Signature> implementation:
template<class Sig> struct recursive; template<class R, class... As> struct recursive< R(As...) > { using base_type = std::function<R(recursive, As...)>; private: std::shared_ptr< base_type > base; public: template<typename...Ts> auto operator()(Ts&&... ts) const -> typename std::result_of< base_type( recursive, Ts... ) >::type { return (*base)(*this, std::forward<Ts>(ts)...); } recursive(recursive const&)=default; recursive(recursive&&)=default; recursive& operator=(recursive const&)=default; recursive& operator=(recursive &&)=default; recursive() = default; template<typename L, typename=typename std::result_of< L(recursive, As...) >::type> explicit recursive( L&& f ): base( std::make_shared<base_type>(std::forward<L>(f))) {} explicit operator bool() const { return base && *base; } };
That is, admittedly, quite difficult. I did a bunch of things to make it more efficient, such an ideal shipment. In addition, unlike std::function , double checks that the type of lambda passing on it matches the signature that it wants.
I believe, but did not confirm that I made it friendly to make the signature lambdas void(auto&&,int) . Does anyone know a fully compatible C ++ 1y online compiler?
The above is just a template. What matters is how it looks in terms of use:
std::function<void (int)> get_recursive_function() { auto f = [] (recursive<void(int)> self, int recurse) { std::cout << recurse << std::endl; if (recurse > 0) { self(recurse - 1); } }; return recursive< void(int) >( f ); };
Here we use the popular auto f = lambda syntax. No need to directly store it in std::function .
Then we explicitly apply it to recursive<void(int)> , which binds it in nodes and removes the recursive<void(int)> argument in f from the front and provides the signature void(int) .
This requires your lambda to take recursive<void(int)> self as its first parameter and do the recursion through it, but that doesn't seem harsh. If I wrote it just to the right , it could work with auto&& self as the first parameter, but I'm not sure.
recursive<?> works for any signature, naturally.
living example
And, with delayed calls in the outer loop , it still works. Please note that I got rid of this global variable (it will work with it as a global variable, it just feels dirty to leave it).
In C ++ 1y, we can eliminate type erasure and shared_ptr overhead that you see above (with the recursive a shared_ptr<function<?>> object). You need to provide a return value since I cannot get result_of to unravel my mess:
struct wrap {}; template<class R, class F> struct recursive { using base_type = F; private: F base; public: template<class... Ts> R operator()(Ts&&... ts) const { return (*base)(*this, std::forward<Ts>(ts)...); } recursive(recursive const&)=default; recursive(recursive&&)=default; recursive& operator=(recursive const&)=default; recursive& operator=(recursive &&)=default; recursive() = delete; template<typename L> recursive( wrap, L&& f ): base( std::forward<L>(f) ) {} }; template<class T>using decay_t = typename std::decay<T>::type; template<class R, class F> recursive<R, decay_t<F>> recurse( F&& f ) { return recursive<R, decay_t<F>>(wrap{}, std::forward<F>(f)); }
Then the get_recursive_function implementation is a little different (where I added some state for fun):
std::function<void (int)> get_recursive_function(int amt) { auto f = [amt] (auto&& self, int count) { std::cout << count << std::endl; if (count > 0) { self(count - amt); } }; return recurse<void>( std::move(f) ); }; int main() { auto f = get_recursive_function(2); f(10); }
using std::function in the return value of get_recursive_function is optional - you can use auto in C ++ 1y. There is still some overhead compared to the ideal version (where the lambda can access its own operator() ) because operator() probably doesn't know that it is called recursively on the same object when it calls self .
It would be tempting to allow operator()( blah ) inside the body of a lambda to allow a recursive call to lambda. This will probably be very little code.