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

Raymond Chen

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.

2 comments

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

  • David Haim 0

    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

  • Rene Stein 0

    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>)

    namespace RStein::Functional
      {
        template
        struct Result_Traits<AsyncCpp::Tasks::Task>
        {
          using Result_Type = AsyncCpp::Tasks::Task;
          using Default_Value_Func = typename AsyncCpp::Tasks::Task::InvalidPlaceholderTaskCreator;
        };  
    

    https://github.com/renestein/Rstein.AsyncCpp/blob/a5a171904cd310e22d2d1aeff57a3d92960cb4aa/RStein.AsyncCpp/Tasks/Task.h#L441

    //Edit: Blog engine apparently eats some characters in the code. 🙁

Feedback usabilla icon