I wish to create a callback that recursively returns itself as a callback.
The suggested method to recurse is for the function to have a reference to itself:
std::function<void (int)> recursive_function = [&] (int recurse) {
std::cout << recurse << std::endl;
if (recurse > 0) {
recursive_function(recurse - 1);
}
};
This fails as soon as you return it from a function:
#include <functional>
#include <iostream>
volatile bool no_optimize = true;
std::function<void (int)> get_recursive_function() {
std::function<void (int)> recursive_function = [&] (int recurse) {
std::cout << recurse << std::endl;
if (recurse > 0) {
recursive_function(recurse - 1);
}
};
if (no_optimize) {
return recursive_function;
}
return [] (int) {};
}
int main(int, char **) {
get_recursive_function()(10);
}
which gives a segmentation fault after outputting 10
because the reference becomes invalid.
How do I do this? I have successfully used what I think is a Y Combinator (which I'll post as an answer), but it is hugely confusing. Is there a better way?
Other attempts
I have tried the boring approach of wrapping it in another layer of callbacks:
#include <functional>
#include <iostream>
#include <memory>
volatile bool no_optimize = true;
std::function<void (int)> get_recursive_function() {
// Closure to allow self-reference
auto recursive_function = [] (int recurse) {
// Actual function that does the work.
std::function<void (int)> function = [&] (int recurse) {
std::cout << recurse << std::endl;
if (recurse > 0) {
function(recurse - 1);
}
};
function(recurse);
};
if (no_optimize) {
return recursive_function;
}
return [] (int) {};
}
int main(int, char **) {
get_recursive_function()(10);
}
but this fails in the actual scenario, where the function is being delayed and called by an outer loop:
#include <functional>
#include <iostream>
#include <memory>
#include <queue>
volatile bool no_optimize = true;
std::queue<std::function<void (void)>> callbacks;
std::function<void (int)> get_recursive_function() {
// Closure to allow self-reference
auto recursive_function = [] (int recurse) {
// Actual function that does the work.
std::function<void (int)> function = [&] (int recurse) {
std::cout << recurse << std::endl;
if (recurse > 0) {
callbacks.push(std::bind(function, recurse - 1));
}
};
function(recurse);
};
if (no_optimize) {
return recursive_function;
}
return [] (int) {};
}
int main(int, char **) {
callbacks.push(std::bind(get_recursive_function(), 10));
while (!callbacks.empty()) {
callbacks.front()();
callbacks.pop();
}
}
which gives 10
, then 9
and then segmentation faults.