Last time, we came up with task-based while loop that involved creating a custom callable that passed copies of itself to the next iteration.
This time, we’ll implement the function in terms of a more traditional recursion.
template<typename Callable>
task<void> do_while_task(
std::shared_ptr<Callable> const& f)
{
return (*f)().then([f](bool loop) {
return loop ? do_while_task(f) :
task_from_result();
});
}
template<typename Callable, typename =
std::enable_if_t<std::is_invocable_v<Callable>>>
task<void> do_while_task(Callable&& callable)
{
using Decayed = std::decay_t<Callable>;
return do_while_task(
std::make_shared<Decayed>(
std::forward<Callable>(callable)));
}
The real work happens in the first overload, which takes a ready-made shared_ptr. The second overload is a convenience method that lets you pass a callable, and it will wrap it in a shared_ptr for you.
However, if you think about it, in PPL-style programming, the lambda callable itself usually holds a pointer to shared state, so that the various task fragments can share information with each other. Let’s look again at my original example.
do_while_task([i = 0, widgets]() mutable
{
if (i >= 3) return task_from_result(false);
return create_widget().then([index = i++, widgets](auto widget)
{
widgets[index] = widget;
return true;
});
}).then([] {
printf("Done!\n");
});
I cheated here and incremented the i variable inside the first lambda, but capturing the unincremented value as index for the second lambda. More realistically, the two lambdas need to share state.
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]() { 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"); });
This means that our do_while_task creates a shared_ptr that itself holds another shared_ptr, which seems kind of silly.
We’ll address this next time.
0 comments