22 General utilities library [utilities] (original) (raw)
22.4 Tuples [tuple]
22.4.1 General [tuple.general]
22.4.2 Header synopsis [tuple.syn]
22.4.3 Concept tuple-like [tuple.like]
22.4.4 Class template tuple [tuple.tuple]
22.4.4.1 General [tuple.tuple.general]
22.4.4.2 Construction [tuple.cnstr]
22.4.4.3 Assignment [tuple.assign]
22.4.4.4 swap [tuple.swap]
22.4.5 Tuple creation functions [tuple.creation]
22.4.6 Calling a function with a tuple of arguments [tuple.apply]
22.4.7 Tuple helper classes [tuple.helper]
22.4.8 Element access [tuple.elem]
22.4.9 Relational operators [tuple.rel]
22.4.10 common_reference related specializations [tuple.common.ref]
22.4.11 Tuple traits [tuple.traits]
22.4.12 Tuple specialized algorithms [tuple.special]
22.4.1 General [tuple.general]
Subclause [tuple] describes the tuple library that provides a tuple type as the class template tuple that can be instantiated with any number of arguments.
Each template argument specifies the type of an element in the tuple.
Consequently, tuples are heterogeneous, fixed-size collections of values.
An instantiation of tuple with two arguments is similar to an instantiation of pair with the same two arguments.
In addition to being available via inclusion of the header,ignore ([tuple.syn]) is available when ([utility]) is included.
22.4.2 Header synopsis [tuple.syn]
22.4.3 Concept tuple-like [tuple.like]
template<class T> concept [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") = _see below_; // _exposition only_
A type T models and satisfies the exposition-only concept tuple-likeif remove_cvref_t<T> is a specialization ofarray, complex, pair, tuple, or ranges::subrange.
22.4.4 Class template tuple [tuple.tuple]
22.4.4.1 General [tuple.tuple.general]
namespace std { template<class... Types> class tuple { public: constexpr explicit(see below) tuple();constexpr explicit(see below) tuple(const Types&...); template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&...); tuple(const tuple&) = default; tuple(tuple&&) = default;template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&);template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&);template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&&);template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&&);template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&); template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&); template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&&); template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&&); template<tuple-like UTuple> constexpr explicit(see below) tuple(UTuple&&);template<class Alloc> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a);template<class Alloc> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const Types&...);template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTypes&&...);template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);template<class Alloc, tuple-like UTuple> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTuple&&);constexpr tuple& operator=(const tuple&);constexpr const tuple& operator=(const tuple&) const;constexpr tuple& operator=(tuple&&) noexcept(see below);constexpr const tuple& operator=(tuple&&) const;template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>&);template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>&) const;template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&&);template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&&) const;template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>&); template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>&) const;template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&&); template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&&) const; template<tuple-like UTuple> constexpr tuple& operator=(UTuple&&);template<tuple-like UTuple> constexpr const tuple& operator=(UTuple&&) const;constexpr void swap(tuple&) noexcept(see below);constexpr void swap(const tuple&) const 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...>;}
If a program declares an explicit or partial specialization of tuple, the program is ill-formed, no diagnostic required.
22.4.4.2 Construction [tuple.cnstr]
In the descriptions that follow, let i be in the range [0, sizeof...(Types)) in order, be the type in Types, and be the type in a template parameter pack named UTypes, where indexing is zero-based.
For each tuple constructor, an exception is thrown only if the construction of one of the types in Types throws an exception.
The defaulted move and copy constructor, respectively, oftuple is a constexpr function if and only if all required element-wise initializations for move and copy, respectively, would be constexpr-suitable ([dcl.constexpr]).
The defaulted move and copy constructor of tuple<> are constexpr functions.
If is_trivially_destructible_v<> is true for all , then the destructor of tuple is trivial.
The default constructor of tuple<> is trivial.
constexpr explicit(_see below_) tuple();
Constraints: is_default_constructible_v<> is true for all i.
Effects: Value-initializes each element.
Remarks: The expression inside explicit evaluates to trueif and only if is not copy-list-initializable from an empty list for at least one i.
[Note 1:
This behavior can be implemented with a trait that checks whether a const & can be initialized with {}.
— _end note_]
constexpr explicit(_see below_) tuple(const Types&...);
Constraints: sizeof...(Types) ≥ 1 andis_copy_constructible_v<> is true for all i.
Effects: Initializes each element with the value of the corresponding parameter.
Remarks: The expression inside explicit is equivalent to:!conjunction_v<is_convertible<const Types&, Types>...>
template<class... UTypes> constexpr explicit(_see below_) tuple(UTypes&&... u);
Let disambiguating-constraint be:
- negation<is_same<remove_cvref_t<>, tuple>>if sizeof...(Types) is 1;
- otherwise,bool_constant<!is_same_v<remove_cvref_t<>, allocator_arg_t> ||is_-
same_v<remove_cvref_t<>, allocator_arg_t>>if sizeof...(Types) is 2 or 3; - otherwise, true_type.
Constraints:
- sizeof...(Types) equals sizeof...(UTypes),
- sizeof...(Types) ≥ 1, and
- conjunction_v<_disambiguating-constraint_, is_constructible<Types, UTypes>...> is
true.
Effects: Initializes the elements in the tuple with the corresponding value in std::forward<UTypes>(u).
Remarks: The expression inside explicit is equivalent to:!conjunction_v<is_convertible<UTypes, Types>...>
This constructor is defined as deleted if(reference_constructs_from_temporary_v<Types, UTypes&&> || ...) is true.
tuple(const tuple& u) = default;
Mandates: is_copy_constructible_v<> is true for all i.
Effects: Initializes each element of *this with the corresponding element of u.
tuple(tuple&& u) = default;
Constraints: is_move_constructible_v<> is true for all i.
Effects: For all i, initializes the element of *this withstd::forward<>(get<i>(u)).
template<class... UTypes> constexpr explicit(_see below_) tuple(tuple<UTypes...>& u);template<class... UTypes> constexpr explicit(_see below_) tuple(const tuple<UTypes...>& u);template<class... UTypes> constexpr explicit(_see below_) tuple(tuple<UTypes...>&& u);template<class... UTypes> constexpr explicit(_see below_) tuple(const tuple<UTypes...>&& u);
Let I be the pack 0, 1, …, (sizeof...(Types) - 1).
Let FWD(u) be static_cast<decltype(u)>(u).
Constraints:
- sizeof...(Types) equals sizeof...(UTypes), and
- (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...)is true, and
- either sizeof...(Types) is not 1, or (when Types... expands to T andUTypes... expands to U)is_convertible_v<decltype(u), T>,is_constructible_v<T, decltype(u)>, andis_same_v<T, U> are all false.
Effects: For all i, initializes the element of *thiswith get<i>(FWD(u)).
Remarks: The expression inside explicit is equivalent to:!(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
The constructor is defined as deleted if(reference_constructs_from_temporary_v<Types, decltype(get<I>(FWD(u)))> || ...) is true.
template<class U1, class U2> constexpr explicit(_see below_) tuple(pair<U1, U2>& u);template<class U1, class U2> constexpr explicit(_see below_) tuple(const pair<U1, U2>& u);template<class U1, class U2> constexpr explicit(_see below_) tuple(pair<U1, U2>&& u);template<class U1, class U2> constexpr explicit(_see below_) tuple(const pair<U1, U2>&& u);
Let FWD(u) be static_cast<decltype(u)>(u).
Constraints:
- sizeof...(Types) is 2,
- is_constructible_v<, decltype(get<0>(FWD(u)))> is true, and
- is_constructible_v<, decltype(get<1>(FWD(u)))> is true.
Effects: Initializes the first element with get<0>(FWD(u)) and the second element with get<1>(FWD(u)).
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<decltype(get<0>(FWD(u))), > || !is_convertible_v<decltype(get<1>(FWD(u))), >
The constructor is defined as deleted ifreference_constructs_from_temporary_v<, decltype(get<0>(FWD(u)))> ||reference_constructs_from_temporary_v<, decltype(get<1>(FWD(u)))> is true.
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr explicit(_see below_) tuple(UTuple&& u);
Let I be the pack 0, 1, …, (sizeof...(Types) - 1).
Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers]) is true,
- remove_cvref_t<UTuple>is not a specialization of ranges::subrange,
- sizeof...(Types)equals tuple_size_v<remove_cvref_t<UTuple>>,
- (is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...)istrue, and
- either sizeof...(Types) is not 1, or (when Types... expands to T)is_convertible_v<UTuple, T> andis_constructible_v<T, UTuple> are both false.
Effects: For all i, initializes the element of *this withget<i>(std::forward<UTuple>(u)).
Remarks: The expression inside explicit is equivalent to:!(is_convertible_v<decltype(get<I>(std::forward<UTuple>(u))), Types> && ...)
The constructor is defined as deleted if(reference_constructs_from_temporary_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> || ...) is true.
template<class Alloc> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a);template<class Alloc> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, const Types&...);template<class Alloc, class... UTypes> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, UTypes&&...);template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);template<class Alloc, class... UTypes> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);template<class Alloc, class... UTypes> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);template<class Alloc, class... UTypes> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);template<class Alloc, class... UTypes> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);template<class Alloc, class U1, class U2> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);template<class Alloc, class U1, class U2> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);template<class Alloc, class U1, class U2> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);template<class Alloc, class U1, class U2> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);template<class Alloc, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr explicit(_see below_) tuple(allocator_arg_t, const Alloc& a, UTuple&&);
22.4.4.3 Assignment [tuple.assign]
For each tuple assignment operator, an exception is thrown only if the assignment of one of the types in Types throws an exception.
In the function descriptions that follow, let i be in the range [0, sizeof...(Types)) in order, be the type in Types, and be the type in a template parameter pack named UTypes, where indexing is zero-based.
constexpr tuple& operator=(const tuple& u);
Effects: Assigns each element of u to the corresponding element of *this.
Remarks: This operator is defined as deleted unlessis_copy_assignable_v<> is true for all i.
constexpr const tuple& operator=(const tuple& u) const;
Constraints: (is_copy_assignable_v<const Types> && ...) is true.
Effects: Assigns each element of u to the corresponding element of *this.
constexpr tuple& operator=(tuple&& u) noexcept(_see below_);
Constraints: is_move_assignable_v<> is true for all i.
Effects: For all i, assigns std::forward<>(get<i>(u)) toget<i>(*this).
Remarks: The exception specification is equivalent to the logical and of the following expressions:is_nothrow_move_assignable_v<> where is the type in Types.
constexpr const tuple& operator=(tuple&& u) const;
Constraints: (is_assignable_v<const Types&, Types> && ...) is true.
Effects: For all i, assigns std::forward<T>(get<i>(u)) to get<i>(*this).
template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- is_assignable_v<&, const &> is true for all i.
Effects: Assigns each element of u to the corresponding element of *this.
template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>& u) const;
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- (is_assignable_v<const Types&, const UTypes&> && ...) is true.
Effects: Assigns each element of u to the corresponding element of *this.
template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- is_assignable_v<&, > is true for all i.
Effects: For all i, assigns std::forward<>(get<i>(u)) toget<i>(*this).
template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&& u) const;
Constraints:
- sizeof...(Types) equals sizeof...(UTypes) and
- (is_assignable_v<const Types&, UTypes> && ...) is true.
Effects: For all i, assigns std::forward<U>(get<i>(u)) to get<i>(*this).
template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
Constraints:
- sizeof...(Types) is 2 and
- is_assignable_v<&, const U1&> is true, and
- is_assignable_v<&, const U2&> is true.
Effects: Assigns u.first to the first element of *thisand u.second to the second element of *this.
template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>& u) const;
Constraints:
- sizeof...(Types) is 2,
- is_assignable_v<const &, const U1&> is true, and
- is_assignable_v<const &, const U2&> is true.
Effects: Assigns u.first to the first element andu.second to the second element.
template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
Constraints:
- sizeof...(Types) is 2 and
- is_assignable_v<&, U1> is true, and
- is_assignable_v<&, U2> is true.
Effects: Assigns std::forward<U1>(u.first) to the first element of *this and
std::forward<U2>(u.second) to the second element of *this.
template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&& u) const;
Constraints:
- sizeof...(Types) is 2,
- is_assignable_v<const &, U1> is true, and
- is_assignable_v<const &, U2> is true.
Effects: Assigns std::forward<U1>(u.first) to the first element and
std::forward<U2>(u.second) to the second element.
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr tuple& operator=(UTuple&& u);
Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers]) is true,
- remove_cvref_t<UTuple>is not a specialization of ranges::subrange,
- sizeof...(Types)equals tuple_size_v<remove_cvref_t<UTuple>>, and
- is_assignable_v<&, decltype(get<i>(std::forward<UTuple>(u)))>is true for all i.
Effects: For all i, assigns get<i>(std::forward<UTuple>(u))to get<i>(*this).
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr const tuple& operator=(UTuple&& u) const;
Constraints:
- different-from<UTuple, tuple> ([range.utility.helpers]) is true,
- remove_cvref_t<UTuple>is not a specialization of ranges::subrange,
- sizeof...(Types)equals tuple_size_v<remove_cvref_t<UTuple>>, and
- is_assignable_v<const &, decltype(get<i>(std::forward<UTuple>(u)))>is true for all i.
Effects: For all i, assignsget<i>(std::forward<UTuple>(u)) to get<i>(*this).
22.4.4.4 swap [tuple.swap]
constexpr void swap(tuple& rhs) noexcept(_see below_);constexpr void swap(const tuple& rhs) const noexcept(_see below_);
Let i be in the range [0, sizeof...(Types)) in order.
Mandates:
- For the first overload,(is_swappable_v<Types> && ...) is true.
- For the second overload,(is_swappable_v<const Types> && ...) is true.
Effects: For each i, calls swap for get<i>(*this) and get<i>(rhs).
Throws: Nothing unless one of the element-wise swap calls throws an exception.
Remarks: The exception specification is equivalent to
- (is_nothrow_swappable_v<Types> && ...) for the first overload and
- (is_nothrow_swappable_v<const Types> && ...) for the second overload.
22.4.5 Tuple creation functions [tuple.creation]
template<class... TTypes> constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&... t);
Returns: tuple<unwrap_ref_decay_t<TTypes>...>(std::forward<TTypes>(t)...).
[Example 1:
int i; float j; make_tuple(1, ref(i), cref(j));creates a tuple of type tuple<int, int&, const float&>.
— _end example_]
template<class... TTypes> constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&... t) noexcept;
Effects: Constructs a tuple of references to the arguments in t suitable for forwarding as arguments to a function.
Because the result may contain references to temporary objects, a program shall ensure that the return value of this function does not outlive any of its arguments (e.g., the program should typically not store the result in a named variable).
Returns: tuple<TTypes&&...>(std::forward<TTypes>(t)...).
template<class... TTypes> constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;
Returns: tuple<TTypes&...>(t...).
[Example 2:
tie functions allow one to create tuples that unpack tuples into variables.
ignore can be used for elements that are not needed:int i; std::string s; tie(i, ignore, s) = make_tuple(42, 3.14, "C++");
— _end example_]
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]")... Tuples> constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
Let n be sizeof...(Tuples).
For every integer :
- Let be the type in Tuples.
- Let be the element in the function parameter pack tpls.
- Let be tuple_element_t<k, >.
- Let be get<k>(std::forward<>()).
- Let be a pack of the types .
- Let be a pack of the expressions .
The types in CTypes are equal to the ordered sequence of the expanded packs of types..., ..., …, ....
Let celems be the ordered sequence of the expanded packs of expressions..., …, ....
Mandates: (is_constructible_v<CTypes, decltype(celems)> && ...) is true.
Returns: tuple<CTypes...>(celems...).
22.4.6 Calling a function with a tuple of arguments [tuple.apply]
template<class F, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") Tuple> constexpr apply_result_t<F, Tuple> apply(F&& f, Tuple&& t) noexcept(is_nothrow_applicable_v<F, Tuple>);
Effects: Given the exposition-only function template:namespace std { template<class F, tuple-like Tuple, size_t... I> constexpr decltype(auto) apply-impl(F&& f, Tuple&& t, index_sequence<I...>) { return INVOKE(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...); } }
Equivalent to:return apply-impl(std::forward<F>(f), std::forward<Tuple>(t), make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
template<class T, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") Tuple> constexpr T make_from_tuple(Tuple&& t);
Mandates: If tuple_size_v<remove_reference_t<Tuple>> is 1, thenreference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))>is false.
Effects: Given the exposition-only function template:namespace std { template<class T, tuple-like Tuple, size_t... I> requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...> constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) { return T(get<I>(std::forward<Tuple>(t))...);} }
Equivalent to:return make-from-tuple-impl<T>( std::forward<Tuple>(t), make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
[Note 1:
The type of T must be supplied as an explicit template parameter, as it cannot be deduced from the argument list.
— _end note_]
22.4.7 Tuple helper classes [tuple.helper]
template<class T> struct tuple_size;
Except where specified otherwise, all specializations of tuple_size meet theCpp17UnaryTypeTrait requirements ([meta.rqmts]) with a base characteristic of integral_constant<size_t, N>for some N.
template<class... Types> struct tuple_size<tuple<Types...>> : integral_constant<size_t, sizeof...(Types)> { };
template<size_t I, class... Types> struct tuple_element<I, tuple<Types...>> { using type = TI;};
Mandates: I < sizeof...(Types).
Result: TI is the type of the element of Types, where indexing is zero-based.
template<class T> struct tuple_size<const T>;
Let TS denote tuple_size<T> of the cv-unqualified type T.
If the expression TS::value is well-formed when treated as an unevaluated operand, then each specialization of the template meets the Cpp17UnaryTypeTrait requirements ([meta.rqmts]) with a base characteristic ofintegral_constant<size_t, TS::value>
Otherwise, it has no member value.
Access checking is performed as if in a context unrelated to TS and T.
Only the validity of the immediate context of the expression is considered.
[Note 1:
The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such side effects are not in the “immediate context” and can result in the program being ill-formed.
— _end note_]
In addition to being available via inclusion of the header, the template is available when any of the headers,, orare included.
template<size_t I, class T> struct tuple_element<I, const T>;
Let TE denote tuple_element_t<I, T> of the cv-unqualified type T.
Then each specialization of the template meets the Cpp17TransformationTrait requirements ([meta.rqmts]) with a member typedef type that names the type add_const_t<TE>.
In addition to being available via inclusion of the header, the template is available when any of the headers,, orare included.
22.4.8 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; // #1 template<size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>& t) noexcept; // #2 template<size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&& t) noexcept;
Mandates: I < sizeof...(Types).
Returns: A reference to the element of t, where indexing is zero-based.
[Note 1:
For the overload marked #1, if a type T in Types is some reference type X&, the return type is X&, not X&&.
However, if the element type is a non-reference type T, the return type is T&&.
— _end note_]
[Note 2:
Constness is shallow.
For the overload marked #2, if a type T in Types is some reference type X&, the return type is X&, not const X&.
However, if the element type is a non-reference type T, the return type is const T&.
This is consistent with how constness is defined to work for non-static data members of reference type.
— _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;
Mandates: The type T occurs exactly once in Types.
Returns: A reference to the element of t corresponding to the typeT in Types.
[Example 1: const tuple<int, const int, double, double> t(1, 2, 3.4, 5.6);const int& i1 = get<int>(t); const int& i2 = get<const int>(t); const double& d = get<double>(t); — _end example_]
[Note 3:
The reason get is a non-member function is that if this functionality had been provided as a member function, code where the type depended on a template parameter would have required using the template keyword.
— _end note_]
22.4.9 Relational operators [tuple.rel]
template<class... TTypes, class... UTypes> constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);template<class... TTypes, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr bool operator==(const tuple<TTypes...>& t, const UTuple& u);
For the first overload let UTuple be tuple<UTypes...>.
Constraints: For all i, where 0 ≤ i < sizeof...(TTypes),get<i>(t) == get<i>(u) is a valid expression anddecltype(get<i>(t) == get<i>(u)) models boolean-testable.
sizeof...(TTypes) equalstuple_size_v<UTuple>.
Returns: true if get<i>(t) == get<i>(u) for alli, otherwise false.
[Note 1:
If sizeof...(TTypes) equals zero, returns true.
— _end note_]
Remarks:
- The elementary comparisons are performed in order from the zeroth index upwards.
No comparisons or element accesses are performed after the first equality comparison that evaluates tofalse.
template<class... TTypes, class... UTypes> constexpr common_comparison_category_t<_synth-three-way-result_<TTypes, UTypes>...> operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);template<class... TTypes, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> constexpr common_comparison_category_t<_synth-three-way-result_<TTypes, Elems>...> operator<=>(const tuple<TTypes...>& t, const UTuple& u);
For the second overload, Elems denotes the pack of typestuple_element_t<0, UTuple>,tuple_element_t<1, UTuple>, …,tuple_element_t<tuple_size_v<UTuple> - 1, UTuple>.
Effects: Performs a lexicographical comparison between t and u.
If sizeof...(TTypes) equals zero, returns strong_ordering::equal.
Otherwise, equivalent to:if (auto c = synth-three-way(get<0>(t), get<0>(u)); c != 0) return c;return <=> ;where for some ris a tuple containing all but the first element of r.
[Note 2:
The above definition does not require t(or u) to be constructed.
It might not even be possible, as t and u are not required to be copy constructible.
Also, all comparison operator functions are short circuited; they do not perform element accesses beyond what is needed to determine the result of the comparison.
— _end note_]
22.4.10 common_reference related specializations [tuple.common.ref]
In the descriptions that follow:
- Let TTypes be a pack formed by the sequence of tuple_element_t<i, TTuple>for every integer .
- Let UTypes be a pack formed by the sequence of tuple_element_t<i, UTuple>for every integer .
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") TTuple, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple,template<class> class TQual, template<class> class UQual> struct basic_common_reference<TTuple, UTuple, TQual, UQual> { using type = _see below_;};
Constraints:
- TTuple is a specialization of tuple orUTuple is a specialization of tuple.
- is_same_v<TTuple, decay_t<TTuple>> is true.
- is_same_v<UTuple, decay_t<UTuple>> is true.
- tuple_size_v<TTuple> equals tuple_size_v<UTuple>.
- tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>denotes a type.
Result: The member typedef-name type denotes the typetuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>.
template<[_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") TTuple, [_tuple-like_](#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]") UTuple> struct common_type<TTuple, UTuple> { using type = _see below_;};
Constraints:
- TTuple is a specialization of tuple orUTuple is a specialization of tuple.
- is_same_v<TTuple, decay_t<TTuple>> is true.
- is_same_v<UTuple, decay_t<UTuple>> is true.
- tuple_size_v<TTuple> equals tuple_size_v<UTuple>.
- tuple<common_type_t<TTypes, UTypes>...> denotes a type.
Result: The member typedef-name type denotes the type
tuple<common_type_t<TTypes, UTypes>...>.
22.4.11 Tuple traits [tuple.traits]
template<class... Types, class Alloc> struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
[Note 1:
Specialization of this trait informs other library components thattuple can be constructed with an allocator, even though it does not have a nested allocator_type.
— _end note_]
22.4.12 Tuple specialized algorithms [tuple.special]
template<class... Types> constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(_see below_);template<class... Types> constexpr void swap(const tuple<Types...>& x, const tuple<Types...>& y) noexcept(_see below_);
Constraints:
- For the first overload,(is_swappable_v<Types> && ...) is true.
- For the second overload,(is_swappable_v<const Types> && ...) is true.
Effects: As if by x.swap(y).
Remarks: The exception specification is equivalent to:noexcept(x.swap(y))