August 13th, 2020

Working around the requirement that Concurrency Runtime task results must be default-constructible and copyable

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.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Rene Stein

    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. :(

    Read more
  • David Haim

    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