Last time, we shed light on the hidden constraints on the result type in Concurrency Runtime tasks: The result type must have a public default constructor, and it must be copyable.
But what if your desired result type doesn’t satisfy these requirements?
To work around the need for a public default constructor, you can wrap your result type inside something that does have a public default constructor, such as std::optional
.
Concurrency::task<std::optional<T>> t([]() { return T::make(); });
If you produce the result from a lambda, you can just return a T
, and a std::optional<T>
will be constructed from it. If you produce the result from a task_
completion_
event
, you’ll have to use a task_
completion_
event<std::optional<
T>>
. The result of the task will be an optional<T>
, and you can use the dereference operator *
to extract the value. (This assumes that the task always completes with a value, which I assume it does, because that’s what it did before you started down this path.)
To work around the need for copyability, you can wrap the result in a std::shared_ptr<T>
. That way, there is still only one T
object, and all the continuations get the shared copy.
And since std::shared_ptr
has a public default constructor, if your result type falls into both categories (lacks a public default constructor, is not copyable), you can wrap it in a std::shared_ptr<T>
and solve both problems.
An optional type is great for this task. (pun intended) :)
As an alternative, I offer in my library Result_Traits that can be specialized for concrete type.
Specialization for Task (result for Task<Task>)
<code>
https://github.com/renestein/Rstein.AsyncCpp/blob/a5a171904cd310e22d2d1aeff57a3d92960cb4aa/RStein.AsyncCpp/Tasks/Task.h#L441
//Edit: Blog engine apparently eats some characters in the code. :(
I will shamelessly post my library here, concurrencpp, which (although is young) does pretty much what PPL’s tasks do but in a cross platform way.
https://github.com/David-Haim/concurrencpp