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

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.