4160. packaged_task should reject rvalue reference return types

Section: 32.10.10.1 [futures.task.general] Status: New Submitter: Casey Carter Opened: 2024-09-28 Last modified: 2024-10-03

Priority: Not Prioritized

View all issues with New status.

Discussion:

promise, future, and shared_future all refuse rvalue reference types as template arguments (e.g., 32.10.6 [futures.promise] paragraphs 1 and 2), but packaged_task<meow&&()> violates no requirements. Its member get_future returns future<meow&&>, which is ill-formed, but the other member functions appear to be callable. Nonetheless, at least MSVCSTL, libc++, and libstdc++ all fail to compile simple uses of packaged_task with a function type that has an rvalue reference return type (see https://www.godbolt.org/z/5E18nn896).

Presumably the design intent — which the implementers all inferred — is that packaged_task should be ill-formed when get_future is not instantiable. The spec should say so explicitly rather than relying on the fact that one of the basis operations is unusable.

Proposed resolution:

This wording is relative to N4988.

  1. Modify 32.10.10.1 [futures.task.general] as indicated:

    […]

    -2- When the packaged_task object is invoked, its stored task is invoked and the result (whether normal or exceptional) stored in the shared state. Any futures that share the shared state will then be able to access the stored result.

    namespace std {
      template<class> class packaged_task; // not defined
      
      template<class R, class... ArgTypes>
      class packaged_task<R(ArgTypes...)> {
        […]
      };
      
      template<class R, class... ArgTypes>
      packaged_task(R (*)(ArgTypes...)) -> packaged_task<R(ArgTypes...)>;
      
      template<class F> packaged_task(F) -> packaged_task<see below>;
    }
    

    -?- The program is ill-formed if R is an rvalue reference type.