This technically solves your problem:
std::function<void()> func = [&func]{
std::cout << "a\n";
func = []{ std::cout << "b\n"; };
};
But it is not a good plan. The lifetime and behaviour of the std function is tied to a local stack variable. Copies fail to do what you probably want in almost any sense -- they continue to print "a\b"
unless they segfault because the original func
fell out of scope.
To fix this we have to deploy some big guns; to start with, the Queen of functional programming, Ms. Y Combinator:
std::function<void()> func = y_combinate( [](auto&& self){
std::cout << "a\n";
self = []{ std::cout << "b\"; };
} );
The Y Combinator takes a function of the signature F = (F,Args...)->R
, then returns a function of the signature (Args...)->R
. It is how stateless languages manage recursion when you cannot name yourself before you are given a name.
Writing a Y Combinator is easier than you would fear in C++:
template<class F>
struct y_combinator_t {
F f;
template<class...Args>
auto operator()(Args&&...args)
-> typename std::result_of< F&( F&, Args&&... ) >::type
{
return f( f, std::forward<Args>(args)... );
}
};
template<class F>
y_combinator_t<typename std::decay<F>::type> y_combinate( F&& f ) {
return {std::forward<F>(f)};
}
sadly this doesn't work as the type of self
passed to a lambda is actually the type of the original lambda. And the b-printing lambda is an unrelated type. So when you try to self = []{ std::cout << "b\n"; }
you get an error embedded in some relatively deep template spam errors.
Sad; but just a temporary setback.
What we need is a type very difficult to name -- a F = std::function<void(F)>
-- a std::function
that takes as its one argument an instance of an object of the same type.
There is usually no way to do this, but with a bit of template tomfoolery... Here, I did it before.
Then your code reads:
std::function<void()> func = y_combinate( recursive_func< void(own_type&) >([](auto&& self){
std::cout << "a\n";
self = [](auto&&){ std::cout << "b\n"; };
}) );
and a call to a given copy of func
first prints "a\n"
, then each later call prints "b\n"
. Copies of b-printers also print b, but copies of a-printers will print a the first time before transitioning.
Live example.
self
in this code is a recursive_func< void(own_type&) >
, so you can do the same thing within the b-printer as you did in the a-printer.