This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3476. `thread` and `jthread` constructors require that the parameters be move-constructible but never move construct the parameters

Section: 32.4.3.3 [thread.thread.constr], 32.4.4.2 [thread.jthread.cons], 32.9.9 [futures.async] Status: WP Submitter: Billy O'Neal III Opened: 2020-08-18 Last modified: 2020-11-09

Priority: 0

View all other issues in [thread.thread.constr].

View all issues with WP status.

Discussion:

I think this was upgraded to Mandates because C++17 and earlier had "`F` and each `Ti` in `Args` shall satisfy the Cpp17MoveConstructible requirements." And for those, I think the requirement was attempting to make the subsequent `decay-copy` valid. However, the 'Mandating the standard library' papers added `is_constructible` requirements which already serve that purpose; `std::(j)thread` has no reason to move the elements after they have been `decay-copy`'d to transfer to the launched thread.

[2020-08-26; Reflector discussion]

Jonathan noticed that the wording for `std::async` is affected by exactly the same unnecessary move-constructible requirements. The proposed wording has been updated to cope for that as well.

[2020-09-02; Reflector prioritization]

Set priority to 0 and status to Tentatively Ready after five votes in favour during reflector discussions.

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

1. Modify 32.4.3.3 [thread.thread.constr] as indicated:

   >     template<class F, class... Args> explicit thread(F&& f, Args&&... args);

   > > -3- Constraints: `remove_cvref_t<F>` is not the same type as `thread`.

   > > -4- Mandates: The following are all `true`:

   > > 1. (4.1) — `is_constructible_v<decay_t<F>, F>`,

   > > 2. (4.2) — `(is_constructible_v<decay_t<Args>, Args> && ...)`, and

   > > 3. (4.3) — `is_move_constructible_v<decay_t<F>>`,

   > > 4. (4.4) — `(is_move_constructible_v<decay_t<Args>> && ...)`, and

   > > 5. (4.5) — `is_invocable_v<decay_t<F>, decay_t<Args>...>`.

   > > -5- Preconditions: `decay_t<F>` and each type in `decay_t<Args>` meet the Cpp17MoveConstructible requirements.

2. Modify 32.4.4.2 [thread.jthread.cons] as indicated:

   >     template<class F, class... Args> explicit jthread(F&& f, Args&&... args);

   > > -3- Constraints: `remove_cvref_t<F>` is not the same type as `jthread`.

   > > -4- Mandates: The following are all `true`:

   > > 1. (4.1) — `is_constructible_v<decay_t<F>, F>`,

   > > 2. (4.2) — `(is_constructible_v<decay_t<Args>, Args> && ...)`, and

   > > 3. (4.3) — `is_move_constructible_v<decay_t<F>>`,

   > > 4. (4.4) — `(is_move_constructible_v<decay_t<Args>> && ...)`, and

   > > 5. (4.5) — `is_invocable_v<decay_t<F>, decay_t<Args>...> || is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>`.

   > > -5- Preconditions: `decay_t<F>` and each type in `decay_t<Args>` meet the Cpp17MoveConstructible requirements.

3. Modify 32.9.9 [futures.async] as indicated:

   >     template<class F, class... Args>
   >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
   >         async(F&& f, Args&&... args);
   >     template<class F, class... Args>
   >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
   >         async(launch policy, F&& f, Args&&... args);

   > > -2- Mandates: The following are all `true`:

   > > 1. (2.1) — `is_constructible_v<decay_t<F>, F>`,

   > > 2. (2.2) — `(is_constructible_v<decay_t<Args>, Args> && ...)`, and

   > > 3. (2.3) — `is_move_constructible_v<decay_t<F>>`,

   > > 4. (2.4) — `(is_move_constructible_v<decay_t<Args>> && ...)`, and

   > > 5. (2.5) — `is_invocable_v<decay_t<F>, decay_t<Args>...>`.

   > > -3- Preconditions: `decay_t<F>` and each type in `decay_t<Args>` meet the Cpp17MoveConstructible requirements.