23 General utilities library [utilities]

23.7 Variants [variant]

23.7.1 In general [variant.general]

Вариантный объект содержит и управляет временем существования значения. Если variant содержит значение, тип этого значения должен быть одним из типов аргументов шаблона, переданных для варианта. Эти аргументы шаблона называются альтернативами.

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

Любой экземпляр variant в любой момент времени либо содержит значение одного из его альтернативных типов, либо не имеет значения. Когда экземпляр variant содержит значение альтернативного типа T, это означает, что значение типа T, называемое variant объектом contained value, выделяется в хранилище variant объекта. Реализациям не разрешается использовать дополнительное хранилище, такое как динамическая память, для выделения содержащегося значения. Содержимое значение должно быть размещено в области variant хранилища, подходящей для всех типов в Types.... Это определяется реализацией, поддерживаются ли более выровненных типов.

Все типы Types... должны быть (возможно, квалифицированными cv) типами объектов, которые не являются массивами.

Программа, которая реализует определение variant без аргументов шаблона, плохо сформирована.

23.7.3.1 Constructors [variant.ctor]

В описаниях , которые следуют, давайте i быть в диапазоне [0, sizeof...(Types)), и Ti быть ith типа в Types....

constexpr variant() noexcept(see below);

Effects: Создает variant удерживающее значение типа, инициализированное значением T0.

Postconditions: valueless_­by_­exception() есть false и index() есть 0.

Throws: Любое исключение, вызванное инициализацией значения T0.

Remarks: Эта функция должна быть в constexpr том и только в том случае, если инициализация значения альтернативного типа T0 удовлетворяет требованиям для функции constexpr. Выражение внутри noexcept эквивалентно is_­nothrow_­default_­constructible_­v<T0>. Эта функция не будет участвовать в разрешении перегрузки , если is_­default_­constructible_­v<T0> не true. [ Note: См. Также класс monostate. ] end note

variant(const variant& w);

Effects: Если w содержит значение, инициализирует variant для хранения той же альтернативы, что w и, и напрямую инициализирует содержащееся значение с помощью get<j>(w), где j is w.index(). В противном случае инициализирует, variant чтобы не хранить значение.

Throws: Любое исключение, вызванное прямой инициализацией any Ti for all i.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда она is_­copy_­constructible_­v<Ti> предназначена true для всех i.

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

Effects: Если w содержит значение, инициализирует variant для хранения той же альтернативы, что w и, и напрямую инициализирует содержащееся значение с помощью get<j>(std​::​move(w)), где j is w.index(). В противном случае инициализирует, variant чтобы не хранить значение.

Throws: Любое исключение, создаваемое перемещением любого Ti для всех i.

Remarks: Выражение внутри noexcept эквивалентно логическому И is_­nothrow_­move_­constructible_­v<Ti> для всех i. Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда она is_­move_­constructible_­v<Ti> предназначена true для всех i.

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

Позвольте Tj быть типом, который определяется следующим образом: построить мнимую функцию FUN(Ti) для каждого альтернативного типа Ti. Перегрузка, FUN(Tj) выбранная разрешением перегрузки для выражения, FUN(std​::​forward<T>(​t)) определяет альтернативу, Tj которая является типом содержащегося значения после построения.

Effects: Инициализируется *this для хранения альтернативного типа Tj и напрямую инициализирует содержащееся в нем значение, как если бы оно было инициализировано напрямую без использования списка std​::​forward<T>(t).

Postconditions: holds_­alternative<Tj>(*this) есть true.

Throws: Любое исключение, вызванное инициализацией выбранной альтернативы Tj.

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если только is_­same_­v<decay_­t<T>, variant> не будет false, если только decay_­t<T> не является ни специализации , in_­place_­type_­t ни специализации in_­place_­index_­t, если только is_­constructible_­v<Tj, T> не будет true, и если выражение (с того вышеупомянутый набор функций мнимых) хорошо сформированы.FUN(std​::​forward<T>(t)) FUN

[Note:

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

неправильно сформирован, поскольку оба альтернативных типа имеют одинаково жизнеспособный конструктор для аргумента. ] end note

Выражение внутри noexcept эквивалентно is_­nothrow_­constructible_­v<Tj, T>. Если Tjвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

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

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами std​::​forward<Args>(args)....

Postconditions: holds_­alternative<T>(*this) есть true.

Throws: Любое исключение, вызванное вызовом выбранного конструктора T.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только одно вхождение T in Types... и is_­constructible_­v<T, Args...> is true. Если Tвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

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

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами il, std​::​forward<Args>(args)....

Postconditions: holds_­alternative<T>(*this) есть true.

Throws: Любое исключение, вызванное вызовом выбранного конструктора T.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только одно вхождение T in Types... и is_­constructible_­v<T, initializer_­list<U>&, Args...> is true. Если Tвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

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

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка TI с аргументами std​::​forward<Args>(args)....

Postconditions: index() есть I.

Throws: Любое исключение, вызванное вызовом выбранного конструктора TI.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только

  • I меньше чем sizeof...(Types) и

  • is_­constructible_­v<TI, Args...> есть true.

Если TIвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

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

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка TI с аргументами il, std​::​forward<Args>(args)....

Postconditions: index() есть I.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только

  • I меньше чем sizeof...(Types) и

  • is_­constructible_­v<TI, initializer_­list<U>&, Args...> есть true.

Если TIвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

// 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 должны соответствовать требованиям для Allocator.

Effects: Эквивалентен предыдущим конструкторам, за исключением того, что содержащееся значение создается с помощью uses-allocator construction.

23.7.3.2 Destructor [variant.dtor]

~variant();

Effects: Если valueless_­by_­exception() есть false, уничтожает текущее содержащееся значение.

Remarks: Если is_­trivially_­destructible_­v<Ti> == true для всех, Ti то этот деструктор должен быть тривиальным деструктором.

23.7.3.3 Assignment [variant.assign]

variant& operator=(const variant& rhs);

Пусть j будет rhs.index().

Effects:

  • Если ни один из значений *this не rhs имеет значения, эффекта нет. Иначе,

  • если *this содержит значение, но rhs не содержит, уничтожает значение, содержащееся в, *this и устанавливает *this значение, не содержащее значения. Иначе,

  • if index() == jприсваивает значение, содержащееся в, rhs значению, содержащемуся в *this. Иначе,

  • если либо, is_­nothrow_­copy_­constructible_­v<Tj> либо !is_­nothrow_­move_­constructible_­v<Tj> равно true, эквивалентно emplace<j>(get<j>(rhs)). Иначе,

  • эквивалентно operator=(variant(rhs)).

Returns: *this.

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

Remarks: Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда она is_­copy_­constructible_­v<Ti> && is_­copy_­assignable_­v<Ti> предназначена true для всех i.

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

Пусть j будет rhs.index().

Effects:

  • Если ни один из значений *this не rhs имеет значения, эффекта нет. Иначе,

  • если *this содержит значение, но rhs не содержит, уничтожает значение, содержащееся в, *this и устанавливает *this значение, не содержащее значения. Иначе,

  • if index() == jприсваивает get<j>(std​::​move(rhs)) значение, содержащееся в *this. Иначе,

  • эквивалентно emplace<j>(get<j>(std​::​move(rhs))).

Returns: *this.

Remarks: Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда она is_­move_­constructible_­v<Ti> && is_­move_­assignable_­v<Ti> предназначена true для всех i. Выражение внутри noexcept эквивалентно: is_­nothrow_­move_­constructible_­v<Ti> && is_­nothrow_­move_­assignable_­v<Ti> для всех i.

  • Если во время вызова Tjконструкции move вызывается исключение (при j условии rhs.index()), что variant объект не будет иметь значения.

  • Если во время вызова Tjприсваивания перемещения возникает исключение , состояние содержащегося в нем значения определяется гарантией безопасности исключений Tjприсваивания перемещения; index() будет j.

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

Позвольте Tj быть типом, который определяется следующим образом: построить мнимую функцию FUN(Ti) для каждого альтернативного типа Ti. Перегрузка, FUN(Tj) выбранная разрешением перегрузки для выражения, FUN(std​::​forward<T>(​t)) определяет альтернативу, Tj которая является типом содержащегося значения после присвоения.

Effects:

  • Если *this содержит Tj, присваивает std​::​forward<T>(t) значение, содержащееся в *this. Иначе,

  • если is_­nothrow_­constructible_­v<Tj, T> || !is_­nothrow_­move_­constructible_­v<Tj> есть true, эквивалентно emplace<j>(std​::​forward<T>(t)). Иначе,

  • эквивалентно operator=(variant(std​::​forward<T>(t))).

Postconditions: holds_­alternative<Tj>(*this) есть true, с Tj выбранной мнимой функцией разрешения перегрузки, описанной выше.

Returns: *this.

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если только is_­same_­v<decay_­t<T>, variant> не будет false, если только is_­assignable_­v<Tj&, T> && is_­constructible_­v<Tj, T> не будет true, и если выражение FUN(std​::​forward<T>(t))FUN того вышеупомянутый набор функций мнимых) хорошо сформированы.

[Note:

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

неправильно сформирован, поскольку оба альтернативных типа имеют одинаково жизнеспособный конструктор для аргумента. ] end note

Выражение внутри noexcept эквивалентно:

is_nothrow_assignable_v<Tj&, T> && is_nothrow_constructible_v<Tj, T>
  • Если во время присваивания std​::​forward<T>(t) значению, содержащемуся в *this, возникает исключение , состояние содержащегося значения и t определяется гарантией безопасности исключений в выражении присваивания; valueless_­by_­exception() будет false.

  • Если во время инициализации содержащегося значения возникает исключение, variant объект может не содержать значения.

23.7.3.4 Modifiers [variant.mod]

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

Позвольте I быть отсчитываемым от нуля индексом T in Types....

Effects: Эквивалентен: return emplace<I>(std​::​forward<Args>(args)...);

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если is_­constructible_­v<T, Args...> не true, и T встречается ровно один раз в Types....

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

Позвольте I быть отсчитываемым от нуля индексом T in Types....

Effects: Эквивалентен: return emplace<I>(il, std​::​forward<Args>(args)...);

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если is_­constructible_­v<T, initializer_­list<U>&, Args...> не true, и T встречается ровно один раз в Types....

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

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

Effects: Уничтожает текущее содержащееся значение, если valueless_­by_­exception() есть false. Затем инициализирует содержащееся значение, как если бы инициализирует значение типа напрямую без использования списка TI с аргументами std​::​forward<Args>(args)....

Postconditions: index() есть I.

Returns: Ссылка на новое содержащееся значение.

Throws: Любое исключение, возникшее во время инициализации содержащегося значения.

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если is_­constructible_­v<TI, Args...> не true. Если во время инициализации содержащегося значения возникает исключение, variant возможно, значение не содержится.

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: Уничтожает текущее содержащееся значение, если valueless_­by_­exception() есть false. Затем инициализирует содержащееся значение, как если бы инициализирует значение типа напрямую без использования списка TI с аргументами il, std​::​forward<Args>(args)....

Postconditions: index() есть I.

Returns: Ссылка на новое содержащееся значение.

Throws: Любое исключение, возникшее во время инициализации содержащегося значения.

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если is_­constructible_­v<TI, initializer_­list<U>&, Args...> не true. Если во время инициализации содержащегося значения возникает исключение, variant возможно, значение не содержится.

23.7.3.5 Value status [variant.status]

constexpr bool valueless_by_exception() const noexcept;

Effects: Возвращает false тогда и только тогда, когда variant содержит значение.

[ Note: A variant может не содержать значения, если во время присвоения или размещения с изменением типа возникает исключение. Последнее означает, что даже a variant<float, int> может стать valueless_­by_­exception(), например,

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: Если valueless_­by_­exception() есть true, возвращается variant_­npos. В противном случае возвращает отсчитываемый от нуля индекс альтернативы содержащегося значения.

23.7.3.6 Swap [variant.swap]

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

Requires: Lvalues ​​типа Ti должны быть заменяемыми ([swappable.requirements]) и is_­move_­constructible_­v<Ti> должны быть доступны true для всех i.

Effects:

  • если valueless_­by_­exception() && rhs.valueless_­by_­exception() нет эффекта. Иначе,

  • если index() == rhs.index()звонит swap(get<i>(*this), get<i>(rhs)) где i есть index(). Иначе,

  • обменивает значения rhs и *this.

Throws: Если index() == rhs.index(), какое-либо исключение, созданное swap(get<i>(*this), get<i>(rhs)) с i be index(). В противном случае любое исключение, созданное конструктором перемещения объекта Ti или Tj with i being index() and j being rhs.index().

Remarks: Если во время вызова функции выбрасывается исключение swap(get<i>(*this), get<i>(rhs)), состояния содержащихся значений of *this и of rhs определяются гарантией безопасности исключений swap для lvalues ​​of Ti with i being index(). Если во время обмена значениями *this и возникает исключение rhs, состояния значений *this и rhs определяются гарантией безопасности исключений variantконструктора перемещения. Выражение внутри noexcept эквивалентно логическому И is_­nothrow_­move_­constructible_­v<Ti> && is_­nothrow_­swappable_­v<Ti> для всех i.

23.7.4 variant helper classes [variant.helper]

template <class T> struct variant_size;

Remarks: Все специализации variant_­size должны соответствовать UnaryTypeTrait требованиям с базовой характеристикой integral_­constant<size_­t, N> для некоторых 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>;

Обозначим VS через variant_­size<T> cv-неквалифицированный тип T. Тогда каждый из трех шаблонов должен соответствовать UnaryTypeTrait требованиям с базовой характеристикой 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>;

Обозначим VA через variant_­alternative<I, T> cv-неквалифицированный тип T. Затем каждый из трех шаблонов должен соответствовать TransformationTrait требованиям с помощью typedef члена, type который называет следующий тип:

  • для первой специализации add_­const_­t<VA​::​type>,

  • для второй специализации add_­volatile_­t<VA​::​type>, и

  • для третьей специализации add_­cv_­t<VA​::​type>.

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

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

Value: Тип TI.

23.7.5 Value access [variant.get]

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

Requires: Тип T встречается ровно один раз Types.... В противном случае программа имеет неверный формат.

Returns: true if index() равен отсчитываемому от нуля индексу 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). В противном случае программа будет некорректной.

Effects: Если v.index() есть I, возвращает ссылку на объект, хранящийся в variant. В противном случае выдает исключение типа 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: Тип T встречается ровно один раз Types.... В противном случае программа имеет неверный формат.

Effects: Если v содержит значение типа T, возвращает ссылку на это значение. В противном случае выдает исключение типа 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). В противном случае программа будет некорректной.

Returns: Указатель на значение, хранящееся в variant, if v != nullptr и v->index() == I. В противном случае возвращается 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: Тип T встречается ровно один раз Types.... В противном случае программа имеет неверный формат.

Effects: Эквивалентно: return get_­if<i>(v); с i отсчитываемым от нуля индексом 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) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если v.index() != w.index(), false; в противном случае v.valueless_­by_­exception(), если true,; иначе get<i>(v) == get<i>(w) с i бытием v.index().

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

Requires: get<i>(v) != get<i>(w) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если v.index() != w.index(), true; в противном случае v.valueless_­by_­exception(), если false,; иначе get<i>(v) != get<i>(w) с i бытием v.index().

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

Requires: get<i>(v) < get<i>(w) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если w.valueless_­by_­exception(), false; в противном случае v.valueless_­by_­exception(), если true,; в противном случае, если v.index() < w.index(), true; в противном случае v.index() > w.index(), если false,; иначе get<i>(v) < get<i>(w) с i бытием v.index().

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

Requires: get<i>(v) > get<i>(w) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если v.valueless_­by_­exception(), false; в противном случае w.valueless_­by_­exception(), если true,; в противном случае, если v.index() > w.index(), true; в противном случае v.index() < w.index(), если false,; иначе get<i>(v) > get<i>(w) с i бытием v.index().

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

Requires: get<i>(v) <= get<i>(w) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если v.valueless_­by_­exception(), true; в противном случае w.valueless_­by_­exception(), если false,; в противном случае, если v.index() < w.index(), true; в противном случае v.index() > w.index(), если false,; иначе get<i>(v) <= get<i>(w) с i бытием v.index().

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

Requires: get<i>(v) >= get<i>(w) является допустимым выражением, возвращающим тип, в который можно преобразовать boolдля всех i.

Returns: Если w.valueless_­by_­exception(), true; в противном случае v.valueless_­by_­exception(), если false,; в противном случае, если v.index() > w.index(), true; в противном случае v.index() < w.index(), если false,; иначе get<i>(v) >= get<i>(w) с i бытием v.index().

23.7.7 Visitation [variant.visit]

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

Requires: Выражение в Effects: элементе должно быть действительным выражением того же типа и категории значения для всех комбинаций альтернативных типов всех вариантов. В противном случае программа имеет неверный формат.

Effects: Пусть is... будет vars.index().... Возвращает . INVOKE(forward<Visitor>(vis), get<is>(forward<Variants>(vars))...);

Remarks: Тип возврата - это общий тип всех возможных INVOKE выражений Effects: элемента.

Throws: bad_­variant_­access если variant в vars это valueless_­by_­exception().

Complexity: Ибо sizeof...(Variants) <= 1вызов вызываемого объекта реализуется в постоянное время, т. Е. Он не зависит от sizeof...(Types). For sizeof...(Variants) > 1, вызов вызываемого объекта не имеет требований к сложности.

23.7.8 Class monostate [variant.monostate]

struct monostate{};

Класс monostate может служить первым альтернативным типом для, variant чтобы сделать этот variant тип конструктивным по умолчанию.

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 объекты имеют только одно состояние; таким образом, они всегда сравнивают равные. ] end note

23.7.10 Specialized algorithms [variant.specalg]

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

Effects: Эквивалентно v.swap(w).

Remarks: Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда она is_­move_­constructible_­v<Ti> && is_­swappable_­v<Ti> предназначена true для всех i. Выражение внутри noexcept эквивалентно 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;
};

Объекты типа bad_­variant_­access выбрасываются, чтобы сообщить о недействительных доступах к значению variant объекта.

bad_variant_access() noexcept;

Создает bad_­variant_­access объект.

const char* what() const noexcept override;

Returns: An реализации определенных НТБ .

23.7.12 Hash support [variant.hash]

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

Специализация hash<variant<Types...>> включена ([unord.hash]) тогда и только тогда, когда hash<remove_­const_­t<Types>>... включена каждая специализация в . Функции-члены не гарантируются noexcept.

template <> struct hash<monostate>;

Специализация включена ([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 должен быть Allocator.

[ Note: Специализация этого признака сообщает другим компонентам библиотеки, что вариант может быть сконструирован с помощью распределителя, даже если у него нет вложенного allocator_­type. ] end note