34 KiB
[variant.variant]
22 General utilities library [utilities]
22.6 Variants [variant]
22.6.3 Class template variant [variant.variant]
22.6.3.1 General [variant.variant.general]
namespace std {template<class... Types>class variant {public:// [variant.ctor], constructorsconstexpr variant() noexcept(see below); constexpr variant(const variant&); constexpr variant(variant&&) noexcept(see below); templateconstexpr variant(T&&) noexcept(see below); template<class T, class... Args>constexpr explicit variant(in_place_type_t, Args&&...); template<class T, class U, class... Args>constexpr explicit variant(in_place_type_t, initializer_list, Args&&...); template<size_t I, class... Args>constexpr explicit variant(in_place_index_t, Args&&...); template<size_t I, class U, class... Args>constexpr explicit variant(in_place_index_t, initializer_list, Args&&...); // [variant.dtor], destructorconstexpr ~variant(); // [variant.assign], assignmentconstexpr variant& operator=(const variant&); constexpr variant& operator=(variant&&) noexcept(see below); template constexpr variant& operator=(T&&) noexcept(see below); // [variant.mod], modifierstemplate<class T, class... Args>constexpr T& emplace(Args&&...); template<class T, class U, class... Args>constexpr T& emplace(initializer_list, Args&&...); template<size_t I, class... Args>constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&...); template<size_t I, class U, class... Args>constexpr variant_alternative_t<I, variant<Types...>>& emplace(initializer_list, Args&&...); // [variant.status], value statusconstexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // [variant.swap], swapconstexpr void swap(variant&) noexcept(see below); // [variant.visit], visitationtemplate<class Self, class Visitor>constexpr decltype(auto) visit(this Self&&, Visitor&&); template<class R, class Self, class Visitor>constexpr R visit(this Self&&, Visitor&&); };}
Any instance of variant at any given time either holds a value of one of its alternative types or holds no value.
When an instance of variant holds a value of alternative type T, it means that a value of type T, referred to as the variant object's contained value, is nested within ([intro.object]) thevariant object.
All types in Types shall meet the Cpp17Destructible requirements (Table 35).
A program that instantiates the definition of variant with no template arguments is ill-formed.
If a program declares an explicit or partial specialization of variant, the program is ill-formed, no diagnostic required.
22.6.3.2 Constructors [variant.ctor]
In the descriptions that follow, let i be in the range [0, sizeof...(Types)), and Ti be the ith type in Types.
constexpr variant() noexcept(see below);
Constraints: is_default_constructible_v is true.
Effects: Constructs a variant holding a value-initialized value of type T0.
Postconditions: valueless_by_exception() is false and index() is 0.
Throws: Any exception thrown by the value-initialization of T0.
Remarks: This function is constexpr if and only if the value-initialization of the alternative type T0 would be constexpr-suitable ([dcl.constexpr]).
The exception specification is equivalent tois_nothrow_default_constructible_v.
[Note 1:
See also class monostate.
â end note]
constexpr variant(const variant& w);
Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value with GET(w), where j is w.index().
Otherwise, initializes the variant to not hold a value.
Throws: Any exception thrown by direct-initializing any Ti for all i.
Remarks: This constructor is defined as deleted unlessis_copy_constructible_v is true for all i.
If is_trivially_copy_constructible_v is true for all i, this constructor is trivial.
constexpr variant(variant&& w) noexcept(see below);
Constraints: is_move_constructible_v is true for all i.
Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value withGET(std::move(w)), where j is w.index().
Otherwise, initializes the variant to not hold a value.
Throws: Any exception thrown by move-constructing any Ti for all i.
Remarks: The exception specification is equivalent to the logical and ofis_nothrow_move_constructible_v for all i.
If is_trivially_move_constructible_v is true for all i, this constructor is trivial.
template<class T> constexpr variant(T&& t) noexcept(see below);
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)}; is well-formed for some invented variable x.
The overload FUN(Tj) selected by overload resolution for the expression FUN(std::forward(t)) defines the alternative Tj which is the type of the contained value after construction.
Constraints:
sizeof...(Types) is nonzero,
is_same_v<remove_cvref_t, variant> is false,
remove_cvref_t is neither a specialization of in_place_type_t nor a specialization of in_place_index_t,
is_constructible_v<Tj, T> is true, and
the expression FUN(std::forward(t)) (with FUN being the above-mentioned set of imaginary functions) is well-formed. [Note 2: variant<string, string> v("abc"); is ill-formed, as both alternative types have an equally viable constructor for the argument. â end note]
Effects: Initializes *this to hold the alternative type Tj and direct-non-list-initializes the contained value with std::forward(t).
Postconditions: holds_alternative(*this) is true.
Throws: Any exception thrown by the initialization of the selected alternative Tj.
Remarks: The exception specification is equivalent tois_nothrow_constructible_v<Tj, T>.
If Tj's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);
Constraints:
There is exactly one occurrence of T in Types... and
is_constructible_v<T, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type T with std::forward(args)....
Postconditions: holds_alternative(*this) is true.
Throws: Any exception thrown by calling the selected constructor of T.
Remarks: If T's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<class T, class U, class... Args> constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);
Constraints:
There is exactly one occurrence of T in Types... and
is_constructible_v<T, initializer_list&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type T with il, std::forward(args)....
Postconditions: holds_alternative(*this) is true.
Throws: Any exception thrown by calling the selected constructor of T.
Remarks: If T's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);
Constraints:
I is less than sizeof...(Types) and
is_constructible_v<TI, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type TI with std::forward(args)....
Postconditions: index() is I.
Throws: Any exception thrown by calling the selected constructor of TI.
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);
Constraints:
I is less than sizeof...(Types) and
is_constructible_v<TI, initializer_list&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type TI with il, std::forward(args)....
Postconditions: index() is I.
Remarks: If TI's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
22.6.3.3 Destructor [variant.dtor]
constexpr ~variant();
Effects: If valueless_by_exception() is false, destroys the currently contained value.
Remarks: If is_trivially_destructible_v is true for all Ti, then this destructor is trivial.
22.6.3.4 Assignment [variant.assign]
constexpr variant& operator=(const variant& rhs);
Let j be rhs.index().
Effects:
-
If neither *this nor rhs holds a value, there is no effect.
-
Otherwise, if *this holds a value but rhs does not, destroys the value contained in *this and sets *this to not hold a value.
-
Otherwise, if index() == j, assigns the value contained in rhs to the value contained in *this.
-
Otherwise, if either is_nothrow_copy_constructible_v is true oris_nothrow_move_constructible_v is false, equivalent to emplace(GET(rhs)).
-
Otherwise, equivalent to operator=(variant(rhs)).
Postconditions: index() == rhs.index().
Returns: *this.
Remarks: This operator is defined as deleted unlessis_copy_constructible_v &&is_copy_assignable_v is true for all i.
If is_trivially_copy_constructible_v &&is_trivially_copy_assignable_v &&is_trivially_destructible_v is true for all i, this assignment operator is trivial.
constexpr variant& operator=(variant&& rhs) noexcept(see below);
Let j be rhs.index().
Constraints: is_move_constructible_v &&is_move_assignable_v istrue for all i.
Effects:
-
If neither *this nor rhs holds a value, there is no effect.
-
Otherwise, if *this holds a value but rhs does not, destroys the value contained in *this and sets *this to not hold a value.
-
Otherwise, if index() == j, assigns GET(std::move(rhs)) to the value contained in *this.
-
Otherwise, equivalent to emplace(GET(std::move(rhs))).
Returns: *this.
Remarks: If is_trivially_move_constructible_v &&is_trivially_move_assignable_v &&is_trivially_destructible_v is true for all i, this assignment operator is trivial.
The exception specification is equivalent tois_nothrow_move_constructible_v && is_nothrow_move_assignable_v for all i.
-
If an exception is thrown during the call to Tj's move construction (with j being rhs.index()), the variant will hold no value.
-
If an exception is thrown during the call to Tj's move assignment, the state of the contained value is as defined by the exception safety guarantee of Tj's move assignment; index() will be j.
template<class T> constexpr variant& operator=(T&& t) noexcept(see below);
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)}; is well-formed for some invented variable x.
The overload FUN(Tj) selected by overload resolution for the expression FUN(std::forward(t)) defines the alternative Tj which is the type of the contained value after assignment.
Constraints:
is_same_v<remove_cvref_t, variant> is false,
is_assignable_v<Tj&, T> && is_constructible_v<Tj, T> is true, and
the expression FUN(std::forward(t)) (with FUN being the above-mentioned set of imaginary functions) is well-formed. [Note 1: variant<string, string> v; v = "abc"; is ill-formed, as both alternative types have an equally viable constructor for the argument. â end note]
Effects:
-
If *this holds a Tj, assigns std::forward(t) to the value contained in *this.
-
Otherwise, if is_nothrow_constructible_v<Tj, T> ||!is_nothrow_move_constructible_v is true, equivalent to emplace(std::forward(t)).
-
Otherwise, equivalent to emplace(Tj(std::forward(t))).
Postconditions: holds_alternative(*this) is true, with Tj selected by the imaginary function overload resolution described above.
Returns: *this.
Remarks: The exception specification is equivalent to:is_nothrow_assignable_v<Tj&, T> && is_nothrow_constructible_v<Tj, T>
-
If an exception is thrown during the assignment of std::forward(t) to the value contained in *this, the state of the contained value andt are as defined by the exception safety guarantee of the assignment expression; valueless_by_exception() will be false.
-
If an exception is thrown during the initialization of the contained value, the variant object is permitted to not hold a value.
22.6.3.5 Modifiers [variant.mod]
template<class T, class... Args> constexpr T& emplace(Args&&... args);
Constraints: is_constructible_v<T, Args...> is true, andT occurs exactly once in Types.
Effects: Equivalent to:return emplace(std::forward(args)...); where I is the zero-based index of T in Types.
template<class T, class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<T, initializer_list&, Args...> is true, and T occurs exactly once in Types.
Effects: Equivalent to:return emplace(il, std::forward(args)...); where I is the zero-based index of T in Types.
template<size_t I, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);
Mandates: I < sizeof...(Types).
Constraints: is_constructible_v<TI, Args...> is true.
Effects: Destroys the currently contained value if valueless_by_exception() is false.
Then direct-non-list-initializes the contained value of type TI with the arguments std::forward(args)....
Postconditions: index() is I.
Returns: A reference to the new contained value.
Throws: Any exception thrown during the initialization of the contained value.
Remarks: If an exception is thrown during the initialization of the contained value, the variant is permitted to not hold a value.
template<size_t I, class U, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);
Mandates: I < sizeof...(Types).
Constraints: is_constructible_v<TI, initializer_list&, Args...> is true.
Effects: Destroys the currently contained value if valueless_by_exception() is false.
Then direct-non-list-initializes the contained value of type TI with il, std::forward(args)....
Postconditions: index() is I.
Returns: A reference to the new contained value.
Throws: Any exception thrown during the initialization of the contained value.
Remarks: If an exception is thrown during the initialization of the contained value, the variant is permitted to not hold a value.
22.6.3.6 Value status [variant.status]
constexpr bool valueless_by_exception() const noexcept;
Effects: Returns false if and only if the variant holds a value.
[Note 1:
It is possible for a variant to hold no value if an exception is thrown during a type-changing assignment or emplacement.
The latter means that even avariant<float, int> can become valueless_by_exception(), for instance bystruct S { operator int() { throw 42; }}; variant<float, int> v{12.f}; v.emplace<1>(S());
â end note]
constexpr size_t index() const noexcept;
Effects: If valueless_by_exception() is true, returns variant_npos.
Otherwise, returns the zero-based index of the alternative of the contained value.
22.6.3.7 Swap [variant.swap]
constexpr void swap(variant& rhs) noexcept(see below);
Mandates: is_move_constructible_v is true for all i.
Preconditions: Each Ti meets the Cpp17Swappable requirements ([swappable.requirements]).
Effects:
-
If valueless_by_exception() && rhs.valueless_by_exception() no effect.
-
Otherwise, if index() == rhs.index(), calls swap(GET(*this), GET(rhs)) where i is index().
-
Otherwise, exchanges values of rhs and *this.
Throws: If index() == rhs.index(), any exception thrown by swap(GET(*this), GET(rhs)) with i being index().
Otherwise, any exception thrown by the move constructor of Ti or Tj with i being index() and j being rhs.index().
Remarks: If an exception is thrown during the call to function swap(GET(*this), GET(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues ofTi with i being index().
If an exception is thrown during the exchange of the values of *this and rhs, the states of the values of *this and of rhs are determined by the exception safety guarantee of variant's move constructor.
The exception specification is equivalent to the logical and ofis_nothrow_move_constructible_v && is_nothrow_swappable_v for all i.