Last time, we wrote a task-based while loop using recursion, using a shared_ptr to pass state, and we noted a redundancy in that we created a shared_ptr to a lambda that in turn held a shared_ptr.
We can eliminate the nested shared pointers by requiring that all the state live inside a caller-provided shared_ptr, levaing the callable stateless.
template<typename State>
task<void> do_while_task(
std::shared_ptr<State> const& state,
bool (*f)(std::shared_ptr<State> const&)
{
return f(state).then([state, f](bool loop) {
return loop ? do_while_task(state, f) :
task_from_result();
});
}
struct lambda_state
{
lambda_state(Widgets* w) : widgets(w) {}
Widgets* widgets;
int i = 0;
};
auto state = std::make_shared<lambda_state>(widgets);
do_while_task(state, [](auto&& state)
{
if (state->i >= 3) return task_from_result(false);
return create_widget().then([state](auto widget)
{
state->widgets[state->i] = widget;
state->i++;
return true;
}
}).then([] {
printf("Done!\n");
});
We can get rid of all the state-> prefixes by making the state be invocable.
template<typename State>
task<void> do_while_task(
std::shared_ptr<State> const& state)
{
return (*state)().then([state](bool loop) {
return loop ? do_while_task(state) :
task_from_result();
});
}
struct lambda_state
: std::enable_shared_from_this<lambda_state>
{
lambda_state(Widgets* w) : widgets(w) {}
Widgets* widgets;
int i = 0;
task<bool> operator()()
{
if (i >= 3) return task_from_result(false);
return create_widget().then(
[this, lifetime = shared_from_this()](auto widget)
{
widgets[i] = widget;
i++;
return true;
});
}
};
auto state = std::make_shared<lambda_state>(widgets);
do_while_task(state).then([] {
printf("Done!\n");
});
Hey, we’ve come full circle! The only difference is that we used enable_ so that the lambda_state could obtain a shared_ptr to itself.
Next time, we’ll translate all this nonsense into C# and JavaScript.
0 comments