23 General utilities library [utilities]

23.7 Variants [variant]

23.7.1 In general [variant.general]

A variant object holds and manages the lifetime of a value. If the variant holds a value, that value's type has to be one of the template argument types given to variant. These template arguments are called alternatives.

23.7.2 Header <variant> synopsis [variant.syn]

namespace std {
  // [variant.variant], class template variant
  template <class... Types>
    class variant;

  // [variant.helper], variant helper classes
  template <class T> struct variant_size;                   // not defined
  template <class T> struct variant_size<const T>;
  template <class T> struct variant_size<volatile T>;
  template <class T> struct variant_size<const volatile T>;
  template <class T>
    inline constexpr size_t variant_size_v = variant_size<T>::value;

  template <class... Types>
    struct variant_size<variant<Types...>>;

  template <size_t I, class T> struct variant_alternative;  // not defined
  template <size_t I, class T> struct variant_alternative<I, const T>;
  template <size_t I, class T> struct variant_alternative<I, volatile T>;
  template <size_t I, class T> struct variant_alternative<I, const volatile T>;
  template <size_t I, class T>
    using variant_alternative_t = typename variant_alternative<I, T>::type;

  template <size_t I, class... Types>
    struct variant_alternative<I, variant<Types...>>;

  inline constexpr size_t variant_npos = -1;

  // [variant.get], value access
  template <class T, class... Types>
    constexpr bool holds_alternative(const variant<Types...>&) noexcept;

  template <size_t I, class... Types>
    constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>&);
  template <size_t I, class... Types>
    constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&);
  template <size_t I, class... Types>
    constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>&);
  template <size_t I, class... Types>
    constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&&);

  template <class T, class... Types>
    constexpr T& get(variant<Types...>&);
  template <class T, class... Types>
    constexpr T&& get(variant<Types...>&&);
  template <class T, class... Types>
    constexpr const T& get(const variant<Types...>&);
  template <class T, class... Types>
    constexpr const T&& get(const variant<Types...>&&);

  template <size_t I, class... Types>
    constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>>
      get_if(variant<Types...>*) noexcept;
  template <size_t I, class... Types>
    constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
      get_if(const variant<Types...>*) noexcept;

  template <class T, class... Types>
    constexpr add_pointer_t<T>
      get_if(variant<Types...>*) noexcept;
  template <class T, class... Types>
    constexpr add_pointer_t<const T>
      get_if(const variant<Types...>*) noexcept;

  // [variant.relops], relational operators
  template <class... Types>
    constexpr bool operator==(const variant<Types...>&, const variant<Types...>&);
  template <class... Types>
    constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&);
  template <class... Types>
    constexpr bool operator<(const variant<Types...>&, const variant<Types...>&);
  template <class... Types>
    constexpr bool operator>(const variant<Types...>&, const variant<Types...>&);
  template <class... Types>
    constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&);
  template <class... Types>
    constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&);

  // [variant.visit], visitation
  template <class Visitor, class... Variants>
    constexpr see below visit(Visitor&&, Variants&&...);

  // [variant.monostate], class monostate
  struct monostate;

  // [variant.monostate.relops], monostate relational operators
  constexpr bool operator<(monostate, monostate) noexcept;
  constexpr bool operator>(monostate, monostate) noexcept;
  constexpr bool operator<=(monostate, monostate) noexcept;
  constexpr bool operator>=(monostate, monostate) noexcept;
  constexpr bool operator==(monostate, monostate) noexcept;
  constexpr bool operator!=(monostate, monostate) noexcept;

  // [variant.specalg], specialized algorithms
  template <class... Types>
    void swap(variant<Types...>&, variant<Types...>&) noexcept(see below);

  // [variant.bad.access], class bad_­variant_­access
  class bad_variant_access;

  // [variant.hash], hash support
  template <class T> struct hash;
  template <class... Types> struct hash<variant<Types...>>;
  template <> struct hash<monostate>;

  // [variant.traits], allocator-related traits
  template <class T, class Alloc> struct uses_allocator;
  template <class... Types, class Alloc> struct uses_allocator<variant<Types...>, Alloc>;
}

23.7.3 Class template variant [variant.variant]

namespace std {
  template <class... Types>
    class variant {
    public:
      // [variant.ctor], constructors
      constexpr variant() noexcept(see below);
      variant(const variant&);
      variant(variant&&) noexcept(see below);

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

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

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

      // allocator-extended constructors
      template <class Alloc>
        variant(allocator_arg_t, const Alloc&);
      template <class Alloc>
        variant(allocator_arg_t, const Alloc&, const variant&);
      template <class Alloc>
        variant(allocator_arg_t, const Alloc&, variant&&);
      template <class Alloc, class T>
        variant(allocator_arg_t, const Alloc&, T&&);
      template <class Alloc, class T, class... Args>
        variant(allocator_arg_t, const Alloc&, in_place_type_t<T>, Args&&...);
      template <class Alloc, class T, class U, class... Args>
        variant(allocator_arg_t, const Alloc&, in_place_type_t<T>,
                initializer_list<U>, Args&&...);
      template <class Alloc, size_t I, class... Args>
        variant(allocator_arg_t, const Alloc&, in_place_index_t<I>, Args&&...);
      template <class Alloc, size_t I, class U, class... Args>
        variant(allocator_arg_t, const Alloc&, in_place_index_t<I>,
                initializer_list<U>, Args&&...);

      // [variant.dtor], destructor
      ~variant();

      // [variant.assign], assignment
      variant& operator=(const variant&);
      variant& operator=(variant&&) noexcept(see below);

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

      // [variant.mod], modifiers
      template <class T, class... Args>
        T& emplace(Args&&...);
      template <class T, class U, class... Args>
        T& emplace(initializer_list<U>, Args&&...);
      template <size_t I, class... Args>
        variant_alternative_t<I, variant<Types...>>& emplace(Args&&...);
      template <size_t I, class U, class... Args>
        variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U>, Args&&...);

      // [variant.status], value status
      constexpr bool valueless_by_exception() const noexcept;
      constexpr size_t index() const noexcept;

      // [variant.swap], swap
      void swap(variant&) noexcept(see below);
    };
}

Any instance of variant at any given time either holds a value of one of its alternative types, or it 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 allocated within the storage of the variant object. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate the contained value. The contained value shall be allocated in a region of the variant storage suitably aligned for all types in Types.... It is implementation-defined whether over-aligned types are supported.

All types in Types... shall be (possibly cv-qualified) object types that are not arrays.

A program that instantiates the definition of variant with no template arguments is ill-formed.

23.7.3.1 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);

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 shall be constexpr if and only if the value-initialization of the alternative type T0 would satisfy the requirements for a constexpr function. The expression inside noexcept is equivalent to is_­nothrow_­default_­constructible_­v<T0>. This function shall not participate in overload resolution unless is_­default_­constructible_­v<T0> is true. [Note: See also class monostate. end note]

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<j>(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 function shall not participate in overload resolution unless is_­copy_­constructible_­v<Ti> is true for all i.

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

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.

Throws: Any exception thrown by move-constructing any Ti for all i.

Remarks: The expression inside noexcept is equivalent to the logical AND of is_­nothrow_­move_­constructible_­v<Ti> for all i. This function shall not participate in overload resolution unless is_­move_­constructible_­v<Ti> is true for all i.

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

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

Postconditions: holds_­alternative<Tj>(*this) is true.

Throws: Any exception thrown by the initialization of the selected alternative Tj.

Remarks: This function shall not participate in overload resolution unless is_­same_­v<decay_­t<T>, variant> is false, unless decay_­t<T> is neither a specialization of in_­place_­type_­t nor a specialization of in_­place_­index_­t, unless is_­constructible_­v<Tj, T> is true, and unless the expression FUN(std​::​forward<T>(t)) (with FUN being the above-mentioned set of imaginary functions) is well formed.

[Note:

variant<string, string> v("abc");

is ill-formed, as both alternative types have an equally viable constructor for the argument. end note]

The expression inside noexcept is equivalent to is_­nothrow_­constructible_­v<Tj, T>. If Tj's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.

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

Effects: Initializes the contained value as if direct-non-list-initializing an object of type T with the arguments std​::​forward<Args>(args)....

Postconditions: holds_­alternative<T>(*this) is true.

Throws: Any exception thrown by calling the selected constructor of T.

Remarks: This function shall not participate in overload resolution unless there is exactly one occurrence of T in Types... and is_­constructible_­v<T, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.

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

Effects: Initializes the contained value as if direct-non-list-initializing an object of type T with the arguments il, std​::​forward<Args>(args)....

Postconditions: holds_­alternative<T>(*this) is true.

Throws: Any exception thrown by calling the selected constructor of T.

Remarks: This function shall not participate in overload resolution unless there is exactly one occurrence of T in Types... and is_­constructible_­v<T, initializer_­list<U>&, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.

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

Effects: Initializes the contained value as if direct-non-list-initializing an object of type TI with the arguments std​::​forward<Args>(args)....

Postconditions: index() is I.

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

Remarks: This function shall not participate in overload resolution unless

  • I is less than sizeof...(Types) and

  • is_­constructible_­v<TI, Args...> is true.

If TI's selected constructor is a constexpr constructor, this constructor shall be 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);

Effects: Initializes the contained value as if direct-non-list-initializing an object of type TI with the arguments il, std​::​forward<Args>(args)....

Postconditions: index() is I.

Remarks: This function shall not participate in overload resolution unless

  • I is less than sizeof...(Types) and

  • is_­constructible_­v<TI, initializer_­list<U>&, Args...> is true.

If TI's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.

// allocator-extended constructors template <class Alloc> variant(allocator_arg_t, const Alloc& a); template <class Alloc> variant(allocator_arg_t, const Alloc& a, const variant& v); template <class Alloc> variant(allocator_arg_t, const Alloc& a, variant&& v); template <class Alloc, class T> variant(allocator_arg_t, const Alloc& a, T&& t); template <class Alloc, class T, class... Args> variant(allocator_arg_t, const Alloc& a, in_place_type_t<T>, Args&&... args); template <class Alloc, class T, class U, class... Args> variant(allocator_arg_t, const Alloc& a, in_place_type_t<T>, initializer_list<U> il, Args&&... args); template <class Alloc, size_t I, class... Args> variant(allocator_arg_t, const Alloc& a, in_place_index_t<I>, Args&&... args); template <class Alloc, size_t I, class U, class... Args> variant(allocator_arg_t, const Alloc& a, in_place_index_t<I>, initializer_list<U> il, Args&&... args);

Requires: Alloc shall meet the requirements for an Allocator.

Effects: Equivalent to the preceding constructors except that the contained value is constructed with uses-allocator construction.

23.7.3.2 Destructor [variant.dtor]

~variant();

Effects: If valueless_­by_­exception() is false, destroys the currently contained value.

Remarks: If is_­trivially_­destructible_­v<Ti> == true for all Ti then this destructor shall be a trivial destructor.

23.7.3.3 Assignment [variant.assign]

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<Tj> or !is_­nothrow_­move_­constructible_­v<Tj> is true, equivalent to emplace<j>(get<j>(rhs)). Otherwise,

  • equivalent to operator=(variant(rhs)).

Returns: *this.

Postconditions: index() == rhs.index().

Remarks: This function shall not participate in overload resolution unless is_­copy_­constructible_­v<Ti> && is_­copy_­assignable_­v<Ti> is true for all i.

variant& operator=(variant&& rhs) noexcept(see below);

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 get<j>(std​::​move(rhs)) to the value contained in *this. Otherwise,

  • equivalent to emplace<j>(get<j>(std​::​move(rhs))).

Returns: *this.

Remarks: This function shall not participate in overload resolution unless is_­move_­constructible_­v<Ti> && is_­move_­assignable_­v<Ti> is true for all i. The expression inside noexcept is equivalent to: is_­nothrow_­move_­constructible_­v<Ti> && is_­nothrow_­move_­assignable_­v<Ti> 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> 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. 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 assignment.

Effects:

  • If *this holds a Tj, assigns std​::​forward<T>(t) to the value contained in *this. Otherwise,

  • if is_­nothrow_­constructible_­v<Tj, T> || !is_­nothrow_­move_­constructible_­v<Tj> is true, equivalent to emplace<j>(std​::​forward<T>(t)). Otherwise,

  • equivalent to operator=(variant(std​::​forward<T>(t))).

Postconditions: holds_­alternative<Tj>(*this) is true, with Tj selected by the imaginary function overload resolution described above.

Returns: *this.

Remarks: This function shall not participate in overload resolution unless is_­same_­v<decay_­t<T>, variant> is false, unless is_­assignable_­v<Tj&, T> && is_­constructible_­v<Tj, T> is true, and unless the expression FUN(std​::​forward<T>(t)) (with FUN being the above-mentioned set of imaginary functions) is well formed.

[Note:

variant<string, string> v;
v = "abc";

is ill-formed, as both alternative types have an equally viable constructor for the argument. end note]

The expression inside noexcept 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>(t) to the value contained in *this, the state of the contained value and t 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 might not hold a value.

23.7.3.4 Modifiers [variant.mod]

template <class T, class... Args> T& emplace(Args&&... args);

Let I be the zero-based index of T in Types....

Effects: Equivalent to: return emplace<I>(std​::​forward<Args>(args)...);

Remarks: This function shall not participate in overload resolution unless is_­constructible_­v<T, Args...> is true, and T occurs exactly once in Types....

template <class T, class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

Let I be the zero-based index of T in Types....

Effects: Equivalent to: return emplace<I>(il, std​::​forward<Args>(args)...);

Remarks: This function shall not participate in overload resolution unless is_­constructible_­v<T, initializer_­list<U>&, Args...> is true, and T occurs exactly once in Types....

template <size_t I, class... Args> variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);

Requires: I < sizeof...(Types).

Effects: Destroys the currently contained value if valueless_­by_­exception() is false. Then initializes the contained value as if direct-non-list-initializing a value of type TI with the arguments std​::​forward<Args>(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: This function shall not participate in overload resolution unless is_­constructible_­v<TI, Args...> is true. If an exception is thrown during the initialization of the contained value, the variant might not hold a value.

template <size_t I, class U, class... Args> variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);

Requires: I < sizeof...(Types).

Effects: Destroys the currently contained value if valueless_­by_­exception() is false. Then initializes the contained value as if direct-non-list-initializing a value of type TI with the arguments il, std​::​forward<Args>(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: This function shall not participate in overload resolution unless is_­constructible_­v<TI, initializer_­list<U>&, Args...> is true. If an exception is thrown during the initialization of the contained value, the variant might not hold a value.

23.7.3.5 Value status [variant.status]

constexpr bool valueless_by_exception() const noexcept;

Effects: Returns false if and only if the variant holds a value.

[Note: A variant might not hold a value if an exception is thrown during a type-changing assignment or emplacement. The latter means that even a variant<float, int> can become valueless_­by_­exception(), for instance by

struct 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.

23.7.3.6 Swap [variant.swap]

void swap(variant& rhs) noexcept(see below);

Requires: Lvalues of type Ti shall be swappable ([swappable.requirements]) and is_­move_­constructible_­v<Ti> shall be true for all i.

Effects:

  • if valueless_­by_­exception() && rhs.valueless_­by_­exception() no effect. Otherwise,

  • if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs)) where i is index(). Otherwise,

  • exchanges values of rhs and *this.

Throws: If index() == rhs.index(), any exception thrown by swap(get<i>(*this), get<i>(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<i>(*this), get<i>(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues of Ti 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 expression inside noexcept is equivalent to the logical AND of is_­nothrow_­move_­constructible_­v<Ti> && is_­nothrow_­swappable_­v<Ti> for all i.

23.7.4 variant helper classes [variant.helper]

template <class T> struct variant_size;

Remarks: All specializations of variant_­size shall meet the UnaryTypeTrait requirements with a base characteristic of integral_­constant<size_­t, N> for some N.

template <class T> class variant_size<const T>; template <class T> class variant_size<volatile T>; template <class T> class variant_size<const volatile T>;

Let VS denote variant_­size<T> of the cv-unqualified type T. Then each of the three templates shall meet the UnaryTypeTrait requirements with a base characteristic of integral_­constant<size_­t, VS​::​value>.

template <class... Types> struct variant_size<variant<Types...>> : integral_constant<size_t, sizeof...(Types)> { };

template <size_t I, class T> class variant_alternative<I, const T>; template <size_t I, class T> class variant_alternative<I, volatile T>; template <size_t I, class T> class variant_alternative<I, const volatile T>;

Let VA denote variant_­alternative<I, T> of the cv-unqualified type T. Then each of the three templates shall meet the TransformationTrait requirements with a member typedef type that names the following type:

  • for the first specialization, add_­const_­t<VA​::​type>,

  • for the second specialization, add_­volatile_­t<VA​::​type>, and

  • for the third specialization, add_­cv_­t<VA​::​type>.

variant_alternative<I, variant<Types...>>::type

Requires: I < sizeof...(Types).

Value: The type TI.

23.7.5 Value access [variant.get]

template <class T, class... Types> constexpr bool holds_alternative(const variant<Types...>& v) noexcept;

Requires: The type T occurs exactly once in Types.... Otherwise, the program is ill-formed.

Returns: true if index() is equal to the zero-based index of T in Types....

template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>& v); template <size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&& v); template <size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>& v); template <size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&& v);

Requires: I < sizeof...(Types). Otherwise the program is ill-formed.

Effects: If v.index() is I, returns a reference to the object stored in the variant. Otherwise, throws an exception of type bad_­variant_­access.

template <class T, class... Types> constexpr T& get(variant<Types...>& v); template <class T, class... Types> constexpr T&& get(variant<Types...>&& v); template <class T, class... Types> constexpr const T& get(const variant<Types...>& v); template <class T, class... Types> constexpr const T&& get(const variant<Types...>&& v);

Requires: The type T occurs exactly once in Types.... Otherwise, the program is ill-formed.

Effects: If v holds a value of type T, returns a reference to that value. Otherwise, throws an exception of type bad_­variant_­access.

template <size_t I, class... Types> constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>* v) noexcept; template <size_t I, class... Types> constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> get_if(const variant<Types...>* v) noexcept;

Requires: I < sizeof...(Types). Otherwise the program is ill-formed.

Returns: A pointer to the value stored in the variant, if v != nullptr and v->index() == I. Otherwise, returns nullptr.

template <class T, class... Types> constexpr add_pointer_t<T> get_if(variant<Types...>* v) noexcept; template <class T, class... Types> constexpr add_pointer_t<const T> get_if(const variant<Types...>* v) noexcept;

Requires: The type T occurs exactly once in Types.... Otherwise, the program is ill-formed.

Effects: Equivalent to: return get_­if<i>(v); with i being the zero-based index of T in Types....

23.7.6 Relational operators [variant.relops]

template <class... Types> constexpr bool operator==(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) == get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If v.index() != w.index(), false; otherwise if v.valueless_­by_­exception(), true; otherwise get<i>(v) == get<i>(w) with i being v.index().

template <class... Types> constexpr bool operator!=(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) != get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If v.index() != w.index(), true; otherwise if v.valueless_­by_­exception(), false; otherwise get<i>(v) != get<i>(w) with i being v.index().

template <class... Types> constexpr bool operator<(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) < get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If w.valueless_­by_­exception(), false; otherwise if v.valueless_­by_­exception(), true; otherwise, if v.index() < w.index(), true; otherwise if v.index() > w.index(), false; otherwise get<i>(v) < get<i>(w) with i being v.index().

template <class... Types> constexpr bool operator>(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) > get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If v.valueless_­by_­exception(), false; otherwise if w.valueless_­by_­exception(), true; otherwise, if v.index() > w.index(), true; otherwise if v.index() < w.index(), false; otherwise get<i>(v) > get<i>(w) with i being v.index().

template <class... Types> constexpr bool operator<=(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) <= get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If v.valueless_­by_­exception(), true; otherwise if w.valueless_­by_­exception(), false; otherwise, if v.index() < w.index(), true; otherwise if v.index() > w.index(), false; otherwise get<i>(v) <= get<i>(w) with i being v.index().

template <class... Types> constexpr bool operator>=(const variant<Types...>& v, const variant<Types...>& w);

Requires: get<i>(v) >= get<i>(w) is a valid expression returning a type that is convertible to bool, for all i.

Returns: If w.valueless_­by_­exception(), true; otherwise if v.valueless_­by_­exception(), false; otherwise, if v.index() > w.index(), true; otherwise if v.index() < w.index(), false; otherwise get<i>(v) >= get<i>(w) with i being v.index().

23.7.7 Visitation [variant.visit]

template <class Visitor, class... Variants> constexpr see below visit(Visitor&& vis, Variants&&... vars);

Requires: The expression in the Effects: element shall be a valid expression of the same type and value category, for all combinations of alternative types of all variants. Otherwise, the program is ill-formed.

Effects: Let is... be vars.index().... Returns INVOKE(forward<Visitor>(vis), get<is>(forward<Variants>(vars))...);.

Remarks: The return type is the common type of all possible INVOKE expressions of the Effects: element.

Throws: bad_­variant_­access if any variant in vars is valueless_­by_­exception().

Complexity: For sizeof...(Variants) <= 1, the invocation of the callable object is implemented in constant time, i.e. it does not depend on sizeof...(Types). For sizeof...(Variants) > 1, the invocation of the callable object has no complexity requirements.

23.7.8 Class monostate [variant.monostate]

struct monostate{};

The class monostate can serve as a first alternative type for a variant to make the variant type default constructible.

23.7.9 monostate relational operators [variant.monostate.relops]

constexpr bool operator<(monostate, monostate) noexcept { return false; } constexpr bool operator>(monostate, monostate) noexcept { return false; } constexpr bool operator<=(monostate, monostate) noexcept { return true; } constexpr bool operator>=(monostate, monostate) noexcept { return true; } constexpr bool operator==(monostate, monostate) noexcept { return true; } constexpr bool operator!=(monostate, monostate) noexcept { return false; }

[Note: monostate objects have only a single state; they thus always compare equal.end note]

23.7.10 Specialized algorithms [variant.specalg]

template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);

Effects: Equivalent to v.swap(w).

Remarks: This function shall not participate in overload resolution unless is_­move_­constructible_­v<Ti> && is_­swappable_­v<Ti> is true for all i. The expression inside noexcept is equivalent to noexcept(v.swap(w)).

23.7.11 Class bad_­variant_­access [variant.bad.access]

class bad_variant_access : public exception {
public:
  bad_variant_access() noexcept;
  const char* what() const noexcept override;
};

Objects of type bad_­variant_­access are thrown to report invalid accesses to the value of a variant object.

bad_variant_access() noexcept;

Constructs a bad_­variant_­access object.

const char* what() const noexcept override;

Returns: An implementation-defined ntbs.

23.7.12 Hash support [variant.hash]

template <class... Types> struct hash<variant<Types...>>;

The specialization hash<variant<Types...>> is enabled ([unord.hash]) if and only if every specialization in hash<remove_­const_­t<Types>>... is enabled. The member functions are not guaranteed to be noexcept.

template <> struct hash<monostate>;

The specialization is enabled ([unord.hash]).

23.7.13 Allocator-related traits [variant.traits]

template <class... Types, class Alloc> struct uses_allocator<variant<Types...>, Alloc> : true_type { };

Requires: Alloc shall be an Allocator.

[Note: Specialization of this trait informs other library components that variant can be constructed with an allocator, even though it does not have a nested allocator_­type. end note]