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

4460. Missing Throws: for last variant constructor

Section: 22.6.3.2 [variant.ctor] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2025-11-07 Last modified: 2025-12-04

Priority: Not Prioritized

View other active issues in [variant.ctor].

View all other issues in [variant.ctor].

View all issues with Tentatively Ready status.

Discussion:

All variant constructors except the last one have a Throws: element saying what they're allowed to throw.

This originates from an editorial pull request, where the submitter said:

"It looks like this defect is an artifact of a change between P0088R0 and P0088R1. Note how in R0 neither one of the emplaced_type_t/emplaced_index_t (as they were then called) + initializer_list constructors have a throws clause. In R1 only one of them gained it."

Previous resolution [SUPERSEDED]:

This wording is relative to N5014.

  1. Modify 22.6.3.2 [variant.ctor], as indicated:

    template<size_t I, class U, class... Args>
      constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);
    

    -35- Constraints:

    1. (35.1) — I is less than sizeof...(Types) and
    2. (35.2) — is_constructible_v<TI, initializer_list<U>&, Args...> is true.

    -36- Effects: Direct-non-list-initializes the contained value of type TI with il, std::forward<Args>(args)....

    -37- Postconditions: index() is I.

    -?- Throws: Any exception thrown by calling the selected constructor of TI.

    -38- Remarks: If TI’s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

[2025-11-11; Jonathan provides improved wording]

[2025-12-04; Reflector poll.]

Set status to Tentatively Ready after six votes in favour during reflector poll.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 22.6.3.2 [variant.ctor], as indicated:

    constexpr variant() noexcept(see below);
    

    -2- Constraints: is_default_constructible_v<T0> is true.

    -3- Effects: Constructs a variant holding a value-initialized value of type T0.

    -4- Postconditions: valueless_by_exception() is false and index() is 0.

    -5- Throws: Any exception thrown by the value-initialization of T0.

    -6- Remarks: […]

    constexpr variant(const variant&);
    

    -7- Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value with GET<j>(w), where j is w.index(). Otherwise, initializes the variant to not hold a value.

    -8- Throws: Any exception thrown by direct-initializating any Ti for all i the initialization of the contained value.

    -9- Remarks: […]

    constexpr variant(variant&&) noexcept(see below);
    

    -10- Constraints: is_move_constructible_v<Ti> is true for all i.

    -11- Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value with GET<j>(std::move(w)), where j is w.index(). Otherwise, initializes the variant to not hold a value.

    -12- Throws: Any exception thrown by move-constructing any Ti for all i the initialization of the contained value.

    -13- Remarks: […]

    template<class T> constexpr variant(T&&) noexcept(see below);
    

    -14- Let Tj be a type that is determined as follows: build an imaginary function FUN(Ti) for each alternative type Ti for which Ti x[] = {std::forward<T>(t)}; is well-formed for some invented variable x. The overload FUN(Tj) selected by overload resolution for the expression FUN(std::forward<T>(t)) defines the alternative Tj which is the type of the contained value after construction.

    -15- Constraints: […]

    -16- Effects: Initializes *this to hold the alternative type Tj and direct-non-list-initializes the contained value with std::forward<T>(t).

    -17- Postconditions: […]

    -18- Throws: Any exception thrown by the initialization of the selected alternative Tj contained value.

    -19- Remarks: […]

    template<class T, class... Args> constexpr variant(in_place_type_t<T>, Args&&... args);
    

    -20- Constraints: […]

    -21- Effects: Direct-non-list-initializes the contained value of type T with std::forward<Args>(args)....

    -22- Postconditions: […]

    -23- Throws: Any exception thrown by the selected constructor of T the initialization of the contained value.

    -24- Remarks: […]

    template<class T, class U, class... Args>
      constexpr variant(in_place_type_t<T>, initializer_list<U> li, Args&&... args);
    

    -25- Constraints: […]

    -26- Effects: Direct-non-list-initializes the contained value of type T with il, std::forward<Args>(args)....

    -27- Postconditions: […]

    -28- Throws: Any exception thrown by the selected constructor of T the initialization of the contained value.

    -29- Remarks: […]

    template<size_t I, class... Args>
      constexpr explicit variant(in_place_index_t<I>, Args&&... args);
    

    -30- Constraints:

    1. (30.1) — I is less than sizeof...(Types) and
    2. (30.2) — is_constructible_v<TI, Args...> is true.

    -31- Effects: Direct-non-list-initializes the contained value of type TI with std::forward<Args>(args)....

    -32- Postconditions: index() is I.

    -33- Throws: Any exception thrown by the selected constructor of Ti the initialization of the contained value.

    -34- Remarks: If TI’s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

    template<size_t I, class U, class... Args>
      constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);
    

    -35- Constraints:

    1. (35.1) — I is less than sizeof...(Types) and
    2. (35.2) — is_constructible_v<TI, initializer_list<U>&, Args...> is true.

    -36- Effects: Direct-non-list-initializes the contained value of type TI with il, std::forward<Args>(args)....

    -37- Postconditions: index() is I.

    -?- Throws: Any exception thrown by the initialization of the contained value.

    -38- Remarks: If TI’s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.