23 General utilities library [utilities]

23.5 Tuples [tuple]

23.5.1 In general [tuple.general]

В этом подпункте описывается библиотека кортежей, которая предоставляет тип кортежа в качестве шаблона класса, tuple который может быть создан с любым количеством аргументов. Каждый аргумент шаблона определяет тип элемента в tuple. Следовательно, кортежи представляют собой разнородные коллекции значений фиксированного размера. Создание экземпляра tuple с двумя аргументами аналогично созданию экземпляра pair с теми же двумя аргументами. Смотрите [pairs].

23.5.2 Header <tuple> synopsis [tuple.syn]

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

  // [tuple.creation], tuple creation functions
  inline constexpr unspecified ignore;

  template <class... TTypes>
    constexpr tuple<VTypes...> make_tuple(TTypes&&...);

  template <class... TTypes>
    constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept;

  template<class... TTypes>
    constexpr tuple<TTypes&...> tie(TTypes&...) noexcept;

  template <class... Tuples>
    constexpr tuple<CTypes...> tuple_cat(Tuples&&...);

  // [tuple.apply], calling a function with a tuple of arguments
  template <class F, class Tuple>
    constexpr decltype(auto) apply(F&& f, Tuple&& t);

  template <class T, class Tuple>
    constexpr T make_from_tuple(Tuple&& t);

  // [tuple.helper], tuple helper classes
  template <class T> class tuple_size;                  // not defined
  template <class T> class tuple_size<const T>;
  template <class T> class tuple_size<volatile T>;
  template <class T> class tuple_size<const volatile T>;

  template <class... Types> class tuple_size<tuple<Types...>>;

  template <size_t I, class T> class tuple_element;     // not defined
  template <size_t I, class T> class tuple_element<I, const T>;
  template <size_t I, class T> class tuple_element<I, volatile T>;
  template <size_t I, class T> class tuple_element<I, const volatile T>;

  template <size_t I, class... Types>
    class tuple_element<I, tuple<Types...>>;

  template <size_t I, class T>
    using tuple_element_t = typename tuple_element<I, T>::type;

  // [tuple.elem], element access
  template <size_t I, class... Types>
    constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>&) noexcept;
  template <size_t I, class... Types>
    constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&&) noexcept;
  template <size_t I, class... Types>
    constexpr const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>&) noexcept;
  template <size_t I, class... Types>
    constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&&) noexcept;
  template <class T, class... Types>
    constexpr T& get(tuple<Types...>& t) noexcept;
  template <class T, class... Types>
    constexpr T&& get(tuple<Types...>&& t) noexcept;
  template <class T, class... Types>
    constexpr const T& get(const tuple<Types...>& t) noexcept;
  template <class T, class... Types>
    constexpr const T&& get(const tuple<Types...>&& t) noexcept;

  // [tuple.rel], relational operators
  template<class... TTypes, class... UTypes>
    constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr bool operator<(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr bool operator>(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr bool operator<=(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr bool operator>=(const tuple<TTypes...>&, const tuple<UTypes...>&);

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

  // [tuple.special], specialized algorithms
  template <class... Types>
    void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);

  // [tuple.helper], tuple helper classes
  template <class T>
    inline constexpr size_t tuple_size_v = tuple_size<T>::value;
}

23.5.3 Class template tuple [tuple.tuple]

namespace std {
  template <class... Types>
    class tuple  {
    public:
      // [tuple.cnstr], tuple construction
      EXPLICIT constexpr tuple();
      EXPLICIT constexpr tuple(const Types&...);         // only if sizeof...(Types) >= 1
      template <class... UTypes>
        EXPLICIT constexpr tuple(UTypes&&...);           // only if sizeof...(Types) >= 1

      tuple(const tuple&) = default;
      tuple(tuple&&) = default;

      template <class... UTypes>
        EXPLICIT constexpr tuple(const tuple<UTypes...>&);
      template <class... UTypes>
        EXPLICIT constexpr tuple(tuple<UTypes...>&&);

      template <class U1, class U2>
        EXPLICIT constexpr tuple(const pair<U1, U2>&);   // only if sizeof...(Types) == 2
      template <class U1, class U2>
        EXPLICIT constexpr tuple(pair<U1, U2>&&);        // only if sizeof...(Types) == 2

      // allocator-extended constructors
      template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a);
      template <class Alloc>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
      template <class Alloc, class... UTypes>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
      template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a, const tuple&);
      template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a, tuple&&);
      template <class Alloc, class... UTypes>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
      template <class Alloc, class... UTypes>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
      template <class Alloc, class U1, class U2>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
      template <class Alloc, class U1, class U2>
        EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);

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

      template <class... UTypes>
        tuple& operator=(const tuple<UTypes...>&);
      template <class... UTypes>
        tuple& operator=(tuple<UTypes...>&&);

      template <class U1, class U2>
        tuple& operator=(const pair<U1, U2>&);              // only if sizeof...(Types) == 2
      template <class U1, class U2>
        tuple& operator=(pair<U1, U2>&&);                   // only if sizeof...(Types) == 2

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

  template<class... UTypes>
    tuple(UTypes...) -> tuple<UTypes...>;
  template<class T1, class T2>
    tuple(pair<T1, T2>) -> tuple<T1, T2>;
  template<class Alloc, class... UTypes>
    tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>;
  template<class Alloc, class T1, class T2>
    tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>;
  template<class Alloc, class... UTypes>
    tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>;
}

23.5.3.1 Construction [tuple.cnstr]

Для каждого tuple конструктора создается исключение, только если конструкция одного из типов в Types вызывает исключение.

Конструктор перемещения и копирования по умолчанию, соответственно, tuple должен быть функцией constexpr тогда и только тогда, когда все требуемые поэлементные инициализации для копирования и перемещения, соответственно, будут удовлетворять требованиям для функции constexpr. Конструктор перемещения и копирования по умолчанию tuple<> должен быть функциями constexpr.

Деструктор кортежа должен быть тривиальным деструктором, если (is_­trivially_­destructible_­v<Types> && ...) есть true.

В нижеследующих описаниях конструктора пусть i будет в диапазоне [0, sizeof...(Types)) по порядку, Ti будет ith типом в Typesи Ui будет ith типом в названном пакете параметров шаблона UTypes, где индексирование отсчитывается от нуля.

EXPLICIT constexpr tuple();

Effects: Значение инициализирует каждый элемент.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, кроме случаев, когда он is_­default_­constructible_­v<Ti> предназначен true для всех i. [ Note: Это поведение может быть реализовано с помощью шаблона конструктора с аргументами шаблона по умолчанию. ] Конструктор является явным тогда и только тогда, когда он не может быть неявно сконструирован по умолчанию хотя бы для одного . [ Это поведение может быть реализовано с помощью трейта, который проверяет, можно ли инициализировать с помощью . ] end note Ti iNote: const Ti& {} end note

EXPLICIT constexpr tuple(const Types&...);

Effects: Инициализирует каждый элемент значением соответствующего параметра.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки , если sizeof...(Types) >= 1 и is_­copy_­constructible_­v<Ti> не true для всех i. Конструктор является явным тогда и только тогда, когда is_­convertible_­v<const Ti&, Ti> он false предназначен хотя бы для одного i.

template <class... UTypes> EXPLICIT constexpr tuple(UTypes&&... u);

Effects: Инициализирует элементы в кортеже с соответствующим значением в std​::​forward<UTypes>(u).

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки , если sizeof...(Types) == sizeof...(UTypes) и sizeof...(Types) >= 1 и is_­constructible_­v<Ti, Ui&&> является true для всех i. Конструктор является явным тогда и только тогда, когда is_­convertible_­v<Ui&&, Ti> он false предназначен хотя бы для одного i.

tuple(const tuple& u) = default;

Requires: is_­copy_­constructible_­v<Ti> это true для всех i.

Effects: Инициализирует каждый элемент *this соответствующего элемента u.

tuple(tuple&& u) = default;

Requires: is_­move_­constructible_­v<Ti> это true для всех i.

Effects: Для всех iинициализирует ith элемент *this with std​::​forward<Ti>(get<i>(u)).

template <class... UTypes> EXPLICIT constexpr tuple(const tuple<UTypes...>& u);

Effects: Инициализирует каждый элемент *this соответствующего элемента u.

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

  • sizeof...(Types) == sizeof...(UTypes) а также

  • is_­constructible_­v<Ti, const Ui&> это true для всех i, и

  • sizeof...(Types) != 1, или (когда Types... расширяется до T и UTypes... расширяется до U)
    !is_­convertible_­v<const tuple<U>&, T> && !is_­constructible_­v<T, const tuple<U>&>
    && !is_­same_­v<T, U>
    равно true.

Конструктор является явным тогда и только тогда, когда is_­convertible_­v<const Ui&, Ti> он false предназначен хотя бы для одного i.

template <class... UTypes> EXPLICIT constexpr tuple(tuple<UTypes...>&& u);

Effects: Для всех iинициализирует ith элемент *this with std​::​forward<Ui>(get<i>(u)).

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

  • sizeof...(Types) == sizeof...(UTypes), а также

  • is_­constructible_­v<Ti, Ui&&> это true для всех i, и

  • sizeof...(Types) != 1, или (когда Types... расширяется до T и UTypes... расширяется до U)
    !is_­convertible_­v<tuple<U>, T> && !is_­constructible_­v<T, tuple<U>> &&
    !is_­same_­v<T, U>
    равно true.

Конструктор является явным тогда и только тогда, когда is_­convertible_­v<Ui&&, Ti> он false предназначен хотя бы для одного i.

template <class U1, class U2> EXPLICIT constexpr tuple(const pair<U1, U2>& u);

Effects: Инициализирует первый элемент с помощью, u.first а второй элемент с помощью u.second.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, за исключением случаев sizeof...(Types) == 2, когда is_­constructible_­v<T0, const U1&> есть true и is_­constructible_­v<T1, const U2&> есть true.

Конструктор является явным тогда и только тогда, когда is_­convertible_­v<const U1&, T0> есть false или is_­convertible_­v<const U2&, T1> есть false.

template <class U1, class U2> EXPLICIT constexpr tuple(pair<U1, U2>&& u);

Effects: Инициализирует первый элемент с помощью, std​::​forward<U1>(u.first) а второй элемент с помощью std​::​forward<U2>(u.second).

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, за исключением случаев sizeof...(Types) == 2, когда is_­constructible_­v<T0, U1&&> есть true и is_­constructible_­v<T1, U2&&> есть true.

Конструктор является явным тогда и только тогда, когда is_­convertible_­v<U1&&, T0> есть false или is_­convertible_­v<U2&&, T1> есть false.

template <class Alloc> tuple(allocator_arg_t, const Alloc& a); template <class Alloc> EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...); template <class Alloc, class... UTypes> EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...); template <class Alloc> tuple(allocator_arg_t, const Alloc& a, const tuple&); template <class Alloc> tuple(allocator_arg_t, const Alloc& a, tuple&&); template <class Alloc, class... UTypes> EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&); template <class Alloc, class... UTypes> EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&); template <class Alloc, class U1, class U2> EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&); template <class Alloc, class U1, class U2> EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);

Requires: Alloc должны соответствовать требованиям для Allocator.

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

23.5.3.2 Assignment [tuple.assign]

Для каждого tuple оператора присваивания исключение выдается только в том случае, если присвоение одного из типов в Types вызывает исключение. В нижеследующих описаниях функций пусть они i находятся в диапазоне [0, sizeof...​(Types)) по порядку, Ti должны быть ith типом в Typesи Ui быть ith типом в названном пакете параметров шаблона UTypes, где индексирование начинается с нуля.

tuple& operator=(const tuple& u);

Effects: Присваивает каждый элемент u к соответствующему элементу *this.

Remarks: Этот оператор должен быть определен как удаленный, если он не is_­copy_­assignable_­v<Ti> предназначен true для всех i.

Returns: *this.

tuple& operator=(tuple&& u) noexcept(see below);

Effects: Для всех i, назначает std​::​forward<Ti>(get<i>(u)) на get<i>(*this).

Remarks: Этот оператор должен быть определен как удаленный, если он не is_­move_­assignable_­v<Ti> предназначен true для всех i.

Remarks: Выражение внутри noexcept эквивалентно логическому и следующих выражений:

is_nothrow_move_assignable_v<Ti>

где Ti это ith тип в Types.

Returns: *this.

template <class... UTypes> tuple& operator=(const tuple<UTypes...>& u);

Effects: Присваивает каждый элемент u к соответствующему элементу *this.

Remarks: Этот оператор не должен участвовать в разрешении перегрузки , если sizeof...(Types) == sizeof...(UTypes) и is_­assignable_­v<Ti&, const Ui&> не true для всех i.

Returns: *this.

template <class... UTypes> tuple& operator=(tuple<UTypes...>&& u);

Effects: Для всех i, назначает std​::​forward<Ui>(get<i>(u)) на get<i>(*this).

Remarks: Этот оператор не должен участвовать в разрешении перегрузки, кроме как is_­assignable_­v<Ti&, Ui&&> == true для всех i и sizeof...(Types) == sizeof...(UTypes).

Returns: *this.

template <class U1, class U2> tuple& operator=(const pair<U1, U2>& u);

Effects: Присваивается u.first первому элементу *this и u.second второму элементу *this.

Remarks: Этот оператор не должен участвовать в разрешении перегрузки , если sizeof...(Types) == 2 и is_­assignable_­v<T0&, const U1&> не true для первого типа T0 в Types и is_­assignable_­v<T1&, const U2&> является true для второго типа T1 в Types.

Returns: *this.

template <class U1, class U2> tuple& operator=(pair<U1, U2>&& u);

Effects: Присваивается std​::​forward<U1>(u.first) первому элементу *this и
std​::​forward<U2>(u.second) второму элементу *this.

Remarks: Этот оператор не должен участвовать в разрешении перегрузки , если sizeof...(Types) == 2 и is_­assignable_­v<T0&, U1&&> не true для первого типа T0 в Types и is_­assignable_­v<T1&, U2&&> является true для второго типа T1 в Types.

Returns: *this.

23.5.3.3 swap [tuple.swap]

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

Requires: Каждый элемент в *this должен быть заменен на ([swappable.requirements]) соответствующий элемент в rhs.

Effects: Вызывает swap каждый элемент в *this и соответствующий ему элемент в rhs.

Remarks: Выражение внутри noexcept эквивалентно логическому и следующих выражений:

is_nothrow_swappable_v<Ti>

где Ti это ith тип в Types.

Throws: Ничего, если один из поэлементных swap вызовов не вызовет исключение.

23.5.3.4 Tuple creation functions [tuple.creation]

В нижеследующих описаниях функций элементы пакета параметров XTypes обозначаются по порядку с помощью Xi for i in [0, sizeof...(XTypes)) , где индексирование начинается с нуля.

template<class... TTypes> constexpr tuple<VTypes...> make_tuple(TTypes&&... t);

Пакет VTypes определяется следующим образом. Пусть Ui будет decay_­t<Ti> для каждого Ti в TTypes. Если Ui - это специализация reference_­wrapper, то Vi в VTypes - Ui​::​type&, иначе Vi - Ui.

Returns: tuple<VTypes...>(std​::​forward<TTypes>(t)...).

[Example:

int i; float j;
make_tuple(1, ref(i), cref(j))

создает кортеж типа tuple<int, int&, const float&>. ] end example

template<class... TTypes> constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&... t) noexcept;

Effects: Создает кортеж ссылок на аргументы, t пригодный для пересылки в качестве аргументов функции. Поскольку результат может содержать ссылки на временные переменные, программа должна гарантировать, что возвращаемое значение этой функции не переживет ни один из ее аргументов (например, программа обычно не должна сохранять результат в именованной переменной).

Returns: tuple<TTypes&&...>(std​::​forward<TTypes>(t)...).

template<class... TTypes> constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;

Returns: tuple<TTypes&...>(t...). Когда аргумент в t is ignore, присвоение любого значения соответствующему элементу кортежа не имеет никакого эффекта.

[ Example: tie функции позволяют создавать кортежи, которые распаковывают кортежи в переменные. ignore можно использовать для элементов, которые не нужны:

int i; std::string s;
tie(i, ignore, s) = make_tuple(42, 3.14, "C++");
// i == 42, s == "C++"

end example]

template <class... Tuples> constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);

В следующих параграфах пусть Ti будет ith типом Tuples, Ui быть remove_­reference_­t<Ti>и tpi будет ith параметром в пакете параметров функции tpls, где все индексации отсчитываются от нуля.

Requires: Для всех i, Ui должен быть тип cvi tuple<Argsi...>, где cvi это (возможно , пустой) и является параметром пакет , представляющий типы элементов в . Позвольте быть типом в . Для всех должны быть выполнены следующие требования: ith cv-qualifier-seq Argsi Ui Aik kth ArgsiAik

  • Если Ti выводится как ссылочный тип lvalue, то в is_­constructible_­v<Aik, cviAik&> == trueпротивном случае

  • is_­constructible_­v<Aik, cviAik&&> == true.

Remarks: Типы в CTypes должны быть равны упорядоченной последовательности расширенных типов Args0..., Args1..., , Argsn1..., где n равно sizeof...(Tuples). Позвольте ei... быть ith упорядоченной последовательностью элементов кортежа результирующего tuple объекта, соответствующей последовательности типов Argsi.

Returns: tuple Объект , построенный по инициализации kith элемента типа eik в ei... с

get<ki>(std::forward<Ti>(tpi))

для каждой действующей ki и каждой группы ei по порядку.

[ Note: Реализация может поддерживать дополнительные типы в пакете параметров, Tuples которые поддерживают tuple-подобный протокол, такие как pair и array. ] end note

23.5.3.5 Calling a function with a tuple of arguments [tuple.apply]

template <class F, class Tuple> constexpr decltype(auto) apply(F&& f, Tuple&& t);

Effects: Учитывая функцию только для экспозиции:

template <class F, class Tuple, size_t... I>
constexpr decltype(auto)
    apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {                // exposition only
  return INVOKE(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}

Эквивалентен:

return apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
                  make_index_sequence<tuple_size_v<decay_t<Tuple>>>{});

template <class T, class Tuple> constexpr T make_from_tuple(Tuple&& t);

Effects: Учитывая функцию только для экспозиции:

template <class T, class Tuple, size_t... I>
constexpr T make_from_tuple_impl(Tuple&& t, index_sequence<I...>) {     // exposition only
  return T(get<I>(std::forward<Tuple>(t))...);
}

Эквивалентен:

return make_from_tuple_impl<T>(forward<Tuple>(t),
                               make_index_sequence<tuple_size_v<decay_t<Tuple>>>{});

[ Note: Тип T должен быть указан как явный параметр шаблона, так как он не может быть выведен из списка аргументов. ] end note

23.5.3.6 Tuple helper classes [tuple.helper]

template <class T> struct tuple_size;

Remarks: Все специализации tuple_­size должны соответствовать UnaryTypeTrait требованиям с базовой характеристикой integral_­constant<size_­t, N> для некоторых N.

template <class... Types> class tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { };

template <size_t I, class... Types> class tuple_element<I, tuple<Types...>> { public: using type = TI; };

Requires: I < sizeof...(Types). Программа некорректно сформирована, если I выходит за пределы допустимого диапазона.

Type: TI - это тип Ith элемента Types, в котором индексирование начинается с нуля.

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

Обозначим TS через tuple_­size<T> - cvнеквалифицированный тип T. Если выражение TS​::​value правильно сформировано, когда рассматривается как неоцененный операнд, то каждый из трех шаблонов должен соответствовать UnaryTypeTrait требованиям с базовой характеристикой

integral_constant<size_t, TS::value>

В противном случае у них не будет ни одного члена value.

Проверка доступа выполняется, как если бы в контексте, не связанном с TS и T. Учитывается только действительность непосредственного контекста выражения. [ Note: Компиляция выражения может привести к побочным эффектам, таким как создание экземпляров специализаций шаблонов классов и специализаций шаблонов функций, создание неявно определенных функций и т. Д. Такие побочные эффекты не относятся к «непосредственному контексту» и могут привести к неправильному формированию программы. ]end note

Помимо того <tuple> , что эти три шаблона доступны через включение заголовка, они доступны либо при включении заголовков, <array> либо <utility> .

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

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

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

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

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

Помимо того <tuple> , что эти три шаблона доступны через включение заголовка, они доступны либо при включении заголовков, <array> либо <utility> .

23.5.3.7 Element access [tuple.elem]

template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>& t) noexcept; template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&& t) noexcept; // Note A template <size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>& t) noexcept; // Note B template <size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&& t) noexcept;

Requires: I < sizeof...(Types). Программа некорректно сформирована, если I выходит за пределы допустимого диапазона.

Returns: Ссылка на Ith элемент t, где индексирование начинается с нуля.

[ Note A: Если T in Types - некоторый ссылочный тип X&, возвращаемый тип - X&нет X&&. Однако, если тип элемента не является ссылочным типом T, возвращается тип T&&. ]end note

[ Note B: Констанс неглубокий. Если T in Types - некоторый ссылочный тип X&, возвращаемый тип - X&not const X&. Однако, если тип элемента не является ссылочным типом T, возвращается тип const T&. Это согласуется с тем, как константность определяется для работы с переменными-членами ссылочного типа. ] end note

template <class T, class... Types> constexpr T& get(tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr T&& get(tuple<Types...>&& t) noexcept; template <class T, class... Types> constexpr const T& get(const tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr const T&& get(const tuple<Types...>&& t) noexcept;

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

Returns: Ссылка на элемент, t соответствующий типу T в Types....

[Example:

  const tuple<int, const int, double, double> t(1, 2, 3.4, 5.6);
  const int& i1 = get<int>(t);        // OK. Not ambiguous. i1 == 1
  const int& i2 = get<const int>(t);  // OK. Not ambiguous. i2 == 2
  const double& d = get<double>(t);   // ERROR. ill-formed

end example]

[ Note: Причина get в том, что функция, не являющаяся членом, состоит в том, что если бы эта функциональность была предоставлена ​​как функция-член, код, в котором тип зависел от параметра шаблона, потребовал бы использования template ключевого слова. ] end note

23.5.3.8 Relational operators [tuple.rel]

template<class... TTypes, class... UTypes> constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Requires: Для всех i, где 0 <= i и i < sizeof...(TTypes), get<i>(t) == get<i>(u) является действительным выражением , возвращающая тип , который конвертируется в bool. sizeof...(TTypes) == sizeof...(UTypes).

Returns: true если get<i>(t) == get<i>(u) для всех i, иначе false. Для любых двух кортежей нулевой длины e и f, e == f возвратов true.

Effects: Элементарные сравнения выполняются в порядке от нулевого индекса вверх. Никакие сравнения или обращения к элементам не выполняются после первого сравнения на равенство, которое оценивается как false.

template<class... TTypes, class... UTypes> constexpr bool operator<(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Requires: Для всех i, where 0 <= i и i < sizeof...(TTypes)оба get<i>(t) < get<i>(u) и get<i>(u) < get<i>(t) являются допустимыми выражениями, возвращающими типы, в которые можно преобразовать bool. sizeof...(TTypes) == sizeof...(UTypes).

Returns: Результат лексикографического сравнения между t и u. Результат определяется как:, (bool)(get<0>(t) < get<0>(u)) || (!(bool)(get<0>(u) < get<0>(t)) && ttail < utail)где rtail для некоторого кортежа r это кортеж, содержащий все элементы, кроме первого r. Для любых двух кортежей нулевой длины e и f, e < f возвратов false.

template<class... TTypes, class... UTypes> constexpr bool operator!=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Returns: !(t == u).

template<class... TTypes, class... UTypes> constexpr bool operator>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Returns: u < t.

template<class... TTypes, class... UTypes> constexpr bool operator<=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Returns: !(u < t).

template<class... TTypes, class... UTypes> constexpr bool operator>=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

Returns: !(t < u).

[ Note: Приведенные выше определения функций сравнения не требуют ttail (или utail) создания. Это может быть даже невозможно, поскольку t и u не обязательно должны быть копируемыми. Кроме того, все функции сравнения замкнуты; они не осуществляют доступ к элементам сверх того, что требуется для определения результата сравнения. ] end note

23.5.3.9 Tuple traits [tuple.traits]

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

Requires: Alloc должен быть Allocator.

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

23.5.3.10 Tuple specialized algorithms [tuple.special]

template <class... Types> void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);

Remarks: Эта функция не должна участвовать в разрешении перегрузки, кроме случаев, когда она is_­swappable_­v<Ti> предназначена true для всех i, где 0i<sizeof...(Types). Выражение внутри noexcept эквивалентно:

noexcept(x.swap(y))

Effects: Как будто мимо x.swap(y).