Files
cppdraft_translate/cppdraft/tuple.md
2025-10-25 03:02:53 +03:00

1666 lines
66 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[tuple]
# 22 General utilities library [[utilities]](./#utilities)
## 22.4 Tuples [tuple]
### [22.4.1](#general) General [[tuple.general]](tuple.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1508)
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[.](#general-1.sentence-1)
Each template argument specifies
the type of an element in the tuple[.](#general-1.sentence-2)
Consequently, tuples are
heterogeneous, fixed-size collections of values[.](#general-1.sentence-3)
An instantiation of tuple with
two arguments is similar to an instantiation of pair with the same two arguments[.](#general-1.sentence-4)
See [[pairs]](pairs "22.3Pairs")[.](#general-1.sentence-5)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1518)
In addition to being available via inclusion of the [<tuple>](#header:%3ctuple%3e "22.4.2Header <tuple> synopsis[tuple.syn]") header,ignore ([[tuple.syn]](#syn "22.4.2Header <tuple> synopsis")) is available when[<utility>](utility.syn#header:%3cutility%3e "22.2.1Header <utility> synopsis[utility.syn]") ([[utility]](utility "22.2Utility components")) is included[.](#general-2.sentence-1)
### [22.4.2](#syn) Header <tuple> synopsis [[tuple.syn]](tuple.syn)
[🔗](#header:%3ctuple%3e)
// all freestanding#include <compare> // see [[compare.syn]](compare.syn "17.12.1Header <compare> synopsis")namespace std {// [[tuple.tuple]](#tuple "22.4.4Class template tuple"), class template tupletemplate<class... Types>class tuple; // [[tuple.like]](#like "22.4.3Concept tuple-like"), concept [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")template<class T>concept [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") = *see below*; // *exposition only*template<class T>concept [*pair-like*](#concept:pair-like "22.4.2Header <tuple> synopsis[tuple.syn]") = // *exposition only*[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")<T> && tuple_size_v<remove_cvref_t<T>> == 2; // [[tuple.common.ref]](#common.ref "22.4.10common_­reference related specializations"), common_reference related specializationstemplate<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") TTuple, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple, template<class> class TQual, template<class> class UQual>struct basic_common_reference<TTuple, UTuple, TQual, UQual>; template<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") TTuple, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>struct common_type<TTuple, UTuple>; // ignorestruct *ignore-type* { // *exposition only*constexpr const *ignore-type*&operator=(const auto &) const noexcept { return *this; }}; inline constexpr *ignore-type* ignore; // [[tuple.creation]](#creation "22.4.5Tuple creation functions"), tuple creation functionstemplate<class... TTypes>constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&...); template<class... TTypes>constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept; template<class... TTypes>constexpr tuple<TTypes&...> tie(TTypes&...) noexcept; template<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")... Tuples>constexpr tuple<CTypes...> tuple_cat(Tuples&&...); // [[tuple.apply]](#apply "22.4.6Calling a function with a tuple of arguments"), calling a function with a tuple of argumentstemplate<class F, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") Tuple>constexpr apply_result_t<F, Tuple> apply(F&& f, Tuple&& t)noexcept(is_nothrow_applicable_v<F, Tuple>); template<class T, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") Tuple>constexpr T make_from_tuple(Tuple&& t); // [[tuple.helper]](#helper "22.4.7Tuple helper classes"), tuple helper classestemplate<class T> struct tuple_size; // *not defined*template<class T> struct tuple_size<const T>; template<class... Types> struct tuple_size<tuple<Types...>>; template<size_t I, class T> struct tuple_element; // *not defined*template<size_t I, class T> struct tuple_element<I, const T>; template<size_t I, class... Types>struct tuple_element<I, tuple<Types...>>; template<size_t I, class T>using [tuple_element_t](#lib:tuple_element_t "22.4.2Header <tuple> synopsis[tuple.syn]") = typename tuple_element<I, T>::type; // [[tuple.elem]](#elem "22.4.8Element access"), element accesstemplate<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]](#rel "22.4.9Relational operators"), relational operatorstemplate<class... TTypes, class... UTypes>constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&); template<class... TTypes, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>constexpr bool operator==(const tuple<TTypes...>&, const UTuple&); template<class... TTypes, class... UTypes>constexpr common_comparison_category_t<*synth-three-way-result*<TTypes, UTypes>...>operator<=>(const tuple<TTypes...>&, const tuple<UTypes...>&); template<class... TTypes, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>constexpr *see below* operator<=>(const tuple<TTypes...>&, const UTuple&); // [[tuple.traits]](#traits "22.4.11Tuple traits"), allocator-related traitstemplate<class... Types, class Alloc>struct uses_allocator<tuple<Types...>, Alloc>; // [[tuple.special]](#special "22.4.12Tuple specialized algorithms"), specialized algorithmstemplate<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*); // [[tuple.helper]](#helper "22.4.7Tuple helper classes"), tuple helper classestemplate<class T>constexpr size_t [tuple_size_v](#lib:tuple_size_v "22.4.2Header <tuple> synopsis[tuple.syn]") = tuple_size<T>::value;}
### [22.4.3](#like) Concept *tuple-like* [[tuple.like]](tuple.like)
[🔗](#concept:tuple-like)
`template<class T>
concept [tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") = see below; // exposition only
`
[1](#like-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1645)
A type T models and satisfies
the exposition-only concept [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") if remove_cvref_t<T> is a specialization ofarray, complex, pair, tuple, or ranges::subrange[.](#like-1.sentence-1)
### [22.4.4](#tuple) Class template tuple [[tuple.tuple]](tuple.tuple)
#### [22.4.4.1](#tuple.general) General [[tuple.tuple.general]](tuple.tuple.general)
[🔗](#lib:tuple_)
namespace std {template<class... Types>class tuple {public:// [[tuple.cnstr]](#cnstr "22.4.4.2Construction"), tuple constructionconstexpr explicit(*see below*) tuple(); constexpr explicit(*see below*) tuple(const Types&...); // only if sizeof...(Types) >= 1template<class... UTypes>constexpr explicit(*see below*) tuple(UTypes&&...); // only if sizeof...(Types) >= 1 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>&); // only if sizeof...(Types) == 2template<class U1, class U2>constexpr explicit(*see below*) tuple(const pair<U1, U2>&); // only if sizeof...(Types) == 2template<class U1, class U2>constexpr explicit(*see below*) tuple(pair<U1, U2>&&); // only if sizeof...(Types) == 2template<class U1, class U2>constexpr explicit(*see below*) tuple(const pair<U1, U2>&&); // only if sizeof...(Types) == 2template<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>constexpr explicit(*see below*) tuple(UTuple&&); // allocator-extended constructorstemplate<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.3Concept tuple-like[tuple.like]") UTuple>constexpr explicit(*see below*) tuple(allocator_arg_t, const Alloc& a, UTuple&&); // [[tuple.assign]](#assign "22.4.4.3Assignment"), tuple assignmentconstexpr 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>&); // only if sizeof...(Types) == 2template<class U1, class U2>constexpr const tuple& operator=(const pair<U1, U2>&) const; // only if sizeof...(Types) == 2template<class U1, class U2>constexpr tuple& operator=(pair<U1, U2>&&); // only if sizeof...(Types) == 2template<class U1, class U2>constexpr const tuple& operator=(pair<U1, U2>&&) const; // only if sizeof...(Types) == 2template<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>constexpr tuple& operator=(UTuple&&); template<[*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>constexpr const tuple& operator=(UTuple&&) const; // [[tuple.swap]](#swap "22.4.4.4swap"), tuple swapconstexpr 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...>;}
[1](#tuple.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1782)
If a program declares an explicit or partial specialization of tuple,
the program is ill-formed, no diagnostic required[.](#tuple.general-1.sentence-1)
#### [22.4.4.2](#cnstr) Construction [[tuple.cnstr]](tuple.cnstr)
[1](#cnstr-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1788)
In the descriptions that follow, let i be in the range
[0, sizeof...(Types)) in order, Ti be the ith type in Types, andUi be the ith type in a template parameter pack named UTypes, where indexing
is zero-based[.](#cnstr-1.sentence-1)
[2](#cnstr-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1795)
For each tuple constructor, an exception is thrown only if the construction of
one of the types in Types throws an exception[.](#cnstr-2.sentence-1)
[3](#cnstr-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1799)
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]](dcl.constexpr "9.2.6The constexpr and consteval specifiers"))[.](#cnstr-3.sentence-1)
The defaulted move and copy constructor of tuple<> are
constexpr functions[.](#cnstr-3.sentence-2)
[4](#cnstr-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1807)
If is_trivially_destructible_v<Ti> is true for all Ti,
then the destructor of tuple is trivial[.](#cnstr-4.sentence-1)
[5](#cnstr-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1811)
The default constructor of tuple<> is trivial[.](#cnstr-5.sentence-1)
[🔗](#lib:tuple,constructor)
`constexpr explicit(see below) tuple();
`
[6](#cnstr-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1820)
*Constraints*: is_default_constructible_v<Ti> is true for all i[.](#cnstr-6.sentence-1)
[7](#cnstr-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1824)
*Effects*: Value-initializes each element[.](#cnstr-7.sentence-1)
[8](#cnstr-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1828)
*Remarks*: The expression inside explicit evaluates to true if and only if Ti is not
copy-list-initializable from an empty list
for at least one i[.](#cnstr-8.sentence-1)
[*Note [1](#cnstr-note-1)*:
This behavior can be implemented with a trait that checks whether
a const Ti& can be initialized with {}[.](#cnstr-8.sentence-2)
— *end note*]
[🔗](#lib:tuple,constructor_)
`constexpr explicit(see below) tuple(const Types&...);
`
[9](#cnstr-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1846)
*Constraints*: sizeof...(Types) ≥ 1 andis_copy_constructible_v<Ti> is true for all i[.](#cnstr-9.sentence-1)
[10](#cnstr-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1851)
*Effects*: Initializes each element with the value of the
corresponding parameter[.](#cnstr-10.sentence-1)
[11](#cnstr-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1856)
*Remarks*: The expression inside explicit is equivalent to:!conjunction_v<is_convertible<const Types&, Types>...>
[🔗](#lib:tuple,constructor__)
`template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u);
`
[12](#cnstr-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1870)
Let *disambiguating-constraint* be:
- [(12.1)](#cnstr-12.1)
negation<is_same<remove_cvref_t<U0>, tuple>> if sizeof...(Types) is 1;
- [(12.2)](#cnstr-12.2)
otherwise,bool_constant<!is_same_v<remove_cvref_t<U0>, allocator_arg_t> || is_-
same_v<remove_cvref_t<T0>, allocator_arg_t>> if sizeof...(Types) is 2 or 3;
- [(12.3)](#cnstr-12.3)
otherwise, true_type[.](#cnstr-12.sentence-1)
[13](#cnstr-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1885)
*Constraints*:
- [(13.1)](#cnstr-13.1)
sizeof...(Types) equals sizeof...(UTypes),
- [(13.2)](#cnstr-13.2)
sizeof...(Types) ≥ 1, and
- [(13.3)](#cnstr-13.3)
conjunction_v<*disambiguating-constraint*,
is_constructible<Types, UTypes>...> is
true[.](#cnstr-13.sentence-1)
[14](#cnstr-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1897)
*Effects*: Initializes the elements in the tuple with the
corresponding value in std::forward<UTypes>(u)[.](#cnstr-14.sentence-1)
[15](#cnstr-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1902)
*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[.](#cnstr-15.sentence-2)
[🔗](#lib:tuple,constructor___)
`tuple(const tuple& u) = default;
`
[16](#cnstr-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1921)
*Mandates*: is_copy_constructible_v<Ti> is true for all i[.](#cnstr-16.sentence-1)
[17](#cnstr-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1925)
*Effects*: Initializes each element of *this with the
corresponding element of u[.](#cnstr-17.sentence-1)
[🔗](#lib:tuple,constructor____)
`tuple(tuple&& u) = default;
`
[18](#cnstr-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1937)
*Constraints*: is_move_constructible_v<Ti> is true for all i[.](#cnstr-18.sentence-1)
[19](#cnstr-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1941)
*Effects*: For all i, initializes the ith element of *this withstd::forward<Ti>(get<i>(u))[.](#cnstr-19.sentence-1)
[🔗](#lib:tuple,constructor_____)
`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);
`
[20](#cnstr-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1956)
Let I be the pack 0, 1, …, (sizeof...(Types) - 1)[.](#cnstr-20.sentence-1)
Let *FWD*(u) be static_cast<decltype(u)>(u)[.](#cnstr-20.sentence-2)
[21](#cnstr-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1960)
*Constraints*:
- [(21.1)](#cnstr-21.1)
sizeof...(Types) equals sizeof...(UTypes), and
- [(21.2)](#cnstr-21.2)
(is_constructible_v<Types, decltype(get<I>(*FWD*(u)))> && ...) is true, and
- [(21.3)](#cnstr-21.3)
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[.](#cnstr-21.sentence-1)
[22](#cnstr-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1977)
*Effects*: For all i, initializes the ith element of *this with get<i>(*FWD*(u))[.](#cnstr-22.sentence-1)
[23](#cnstr-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L1982)
*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[.](#cnstr-23.sentence-2)
[🔗](#lib:tuple,constructor______)
`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);
`
[24](#cnstr-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2004)
Let *FWD*(u) be static_cast<decltype(u)>(u)[.](#cnstr-24.sentence-1)
[25](#cnstr-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2007)
*Constraints*:
- [(25.1)](#cnstr-25.1)
sizeof...(Types) is 2,
- [(25.2)](#cnstr-25.2)
is_constructible_v<T0, decltype(get<0>(*FWD*(u)))> is true, and
- [(25.3)](#cnstr-25.3)
is_constructible_v<T1, decltype(get<1>(*FWD*(u)))> is true[.](#cnstr-25.sentence-1)
[26](#cnstr-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2018)
*Effects*: Initializes the first element with get<0>(*FWD*(u)) and
the second element with get<1>(*FWD*(u))[.](#cnstr-26.sentence-1)
[27](#cnstr-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2023)
*Remarks*: The expression inside explicit is equivalent to:!is_convertible_v<decltype(get<0>(*FWD*(u))), T0> ||!is_convertible_v<decltype(get<1>(*FWD*(u))), T1>
The constructor is defined as deleted ifreference_constructs_from_temporary_v<T0, decltype(get<0>(*FWD*(u)))> || reference_constructs_from_temporary_v<T1, decltype(get<1>(*FWD*(u)))> is true[.](#cnstr-27.sentence-2)
[🔗](#lib:tuple,constructor_______)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>
constexpr explicit(see below) tuple(UTuple&& u);
`
[28](#cnstr-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2045)
Let I be the pack 0, 1, …, (sizeof...(Types) - 1)[.](#cnstr-28.sentence-1)
[29](#cnstr-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2048)
*Constraints*:
- [(29.1)](#cnstr-29.1)
[*different-from*](range.utility.helpers#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<UTuple, tuple> ([[range.utility.helpers]](range.utility.helpers "25.5.2Helper concepts"))
is true,
- [(29.2)](#cnstr-29.2)
remove_cvref_t<UTuple> is not a specialization of ranges::subrange,
- [(29.3)](#cnstr-29.3)
sizeof...(Types) equals tuple_size_v<remove_cvref_t<UTuple>>,
- [(29.4)](#cnstr-29.4)
(is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...) istrue, and
- [(29.5)](#cnstr-29.5)
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[.](#cnstr-29.sentence-1)
[30](#cnstr-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2075)
*Effects*: For all i, initializes the ith element of *this withget<i>(std::forward<UTuple>(u))[.](#cnstr-30.sentence-1)
[31](#cnstr-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2080)
*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[.](#cnstr-31.sentence-2)
[🔗](#lib:tuple,constructor________)
`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.3Concept tuple-like[tuple.like]") UTuple>
constexpr explicit(see below)
tuple(allocator_arg_t, const Alloc& a, UTuple&&);
`
[32](#cnstr-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2139)
*Preconditions*: Alloc meets
the [*Cpp17Allocator*](allocator.requirements.general#:Cpp17Allocator "16.4.4.6.1General[allocator.requirements.general]") requirements ([[allocator.requirements.general]](allocator.requirements.general "16.4.4.6.1General"))[.](#cnstr-32.sentence-1)
[33](#cnstr-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2144)
*Effects*: Equivalent to the preceding constructors except that each element is constructed with[uses-allocator construction](allocator.uses.construction#def:uses-allocator_construction "20.2.8.2Uses-allocator construction[allocator.uses.construction]")[.](#cnstr-33.sentence-1)
#### [22.4.4.3](#assign) Assignment [[tuple.assign]](tuple.assign)
[1](#assign-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2152)
For each tuple assignment operator, an exception is thrown only if the
assignment of one of the types in Types throws an exception[.](#assign-1.sentence-1)
In the function descriptions that follow, let i be in the range [0, sizeof...(Types))
in order, Ti be the ith type in Types,
and Ui be the ith type in a
template parameter pack named UTypes, where indexing is zero-based[.](#assign-1.sentence-2)
[🔗](#lib:operator=,tuple)
`constexpr tuple& operator=(const tuple& u);
`
[2](#assign-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2166)
*Effects*: Assigns each element of u to the corresponding
element of *this[.](#assign-2.sentence-1)
[3](#assign-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2171)
*Returns*: *this[.](#assign-3.sentence-1)
[4](#assign-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2175)
*Remarks*: This operator is defined as deleted unlessis_copy_assignable_v<Ti> is true for all i[.](#assign-4.sentence-1)
[🔗](#lib:operator=,tuple_)
`constexpr const tuple& operator=(const tuple& u) const;
`
[5](#assign-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2187)
*Constraints*: (is_copy_assignable_v<const Types> && ...) is true[.](#assign-5.sentence-1)
[6](#assign-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2191)
*Effects*: Assigns each element of u to the corresponding element of *this[.](#assign-6.sentence-1)
[7](#assign-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2195)
*Returns*: *this[.](#assign-7.sentence-1)
[🔗](#lib:operator=,tuple__)
`constexpr tuple& operator=(tuple&& u) noexcept(see below);
`
[8](#assign-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2206)
*Constraints*: is_move_assignable_v<Ti> is true for all i[.](#assign-8.sentence-1)
[9](#assign-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2210)
*Effects*: For all i, assigns std::forward<Ti>(get<i>(u)) toget<i>(*this)[.](#assign-9.sentence-1)
[10](#assign-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2215)
*Returns*: *this[.](#assign-10.sentence-1)
[11](#assign-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2219)
*Remarks*: The exception specification is equivalent to the logical and of the
following expressions:is_nothrow_move_assignable_v<Ti> where Ti is the ith type in Types[.](#assign-11.sentence-1)
[🔗](#lib:operator=,tuple___)
`constexpr const tuple& operator=(tuple&& u) const;
`
[12](#assign-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2235)
*Constraints*: (is_assignable_v<const Types&, Types> && ...) is true[.](#assign-12.sentence-1)
[13](#assign-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2239)
*Effects*: For all i,
assigns std::forward<Ti>(get<i>(u)) to get<i>(*this)[.](#assign-13.sentence-1)
[14](#assign-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2244)
*Returns*: *this[.](#assign-14.sentence-1)
[🔗](#lib:operator=,tuple____)
`template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
`
[15](#assign-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2255)
*Constraints*:
- [(15.1)](#assign-15.1)
sizeof...(Types) equals sizeof...(UTypes) and
- [(15.2)](#assign-15.2)
is_assignable_v<Ti&, const Ui&> is true for all i[.](#assign-15.sentence-1)
[16](#assign-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2262)
*Effects*: Assigns each element of u to the corresponding element
of *this[.](#assign-16.sentence-1)
[17](#assign-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2267)
*Returns*: *this[.](#assign-17.sentence-1)
[🔗](#lib:operator=,tuple_____)
`template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>& u) const;
`
[18](#assign-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2278)
*Constraints*:
- [(18.1)](#assign-18.1)
sizeof...(Types) equals sizeof...(UTypes) and
- [(18.2)](#assign-18.2)
(is_assignable_v<const Types&, const UTypes&> && ...) is true[.](#assign-18.sentence-1)
[19](#assign-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2287)
*Effects*: Assigns each element of u to the corresponding element of *this[.](#assign-19.sentence-1)
[20](#assign-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2291)
*Returns*: *this[.](#assign-20.sentence-1)
[🔗](#lib:operator=,tuple______)
`template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
`
[21](#assign-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2302)
*Constraints*:
- [(21.1)](#assign-21.1)
sizeof...(Types) equals sizeof...(UTypes) and
- [(21.2)](#assign-21.2)
is_assignable_v<Ti&, Ui> is true for all i[.](#assign-21.sentence-1)
[22](#assign-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2309)
*Effects*: For all i, assigns std::forward<Ui>(get<i>(u)) toget<i>(*this)[.](#assign-22.sentence-1)
[23](#assign-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2314)
*Returns*: *this[.](#assign-23.sentence-1)
[🔗](#lib:operator=,tuple_______)
`template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&& u) const;
`
[24](#assign-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2325)
*Constraints*:
- [(24.1)](#assign-24.1)
sizeof...(Types) equals sizeof...(UTypes) and
- [(24.2)](#assign-24.2)
(is_assignable_v<const Types&, UTypes> && ...) is true[.](#assign-24.sentence-1)
[25](#assign-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2334)
*Effects*: For all i,
assigns std::forward<Ui>(get<i>(u)) to get<i>(*this)[.](#assign-25.sentence-1)
[26](#assign-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2339)
*Returns*: *this[.](#assign-26.sentence-1)
[🔗](#lib:operator=,tuple________)
`template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
`
[27](#assign-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2351)
*Constraints*:
- [(27.1)](#assign-27.1)
sizeof...(Types) is 2 and
- [(27.2)](#assign-27.2)
is_assignable_v<T0&, const U1&> is true, and
- [(27.3)](#assign-27.3)
is_assignable_v<T1&, const U2&> is true[.](#assign-27.sentence-1)
[28](#assign-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2359)
*Effects*: Assigns u.first to the first element of *this and u.second to the second element of *this[.](#assign-28.sentence-1)
[29](#assign-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2364)
*Returns*: *this[.](#assign-29.sentence-1)
[🔗](#lib:operator=,tuple_________)
`template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>& u) const;
`
[30](#assign-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2375)
*Constraints*:
- [(30.1)](#assign-30.1)
sizeof...(Types) is 2,
- [(30.2)](#assign-30.2)
is_assignable_v<const T0&, const U1&> is true, and
- [(30.3)](#assign-30.3)
is_assignable_v<const T1&, const U2&> is true[.](#assign-30.sentence-1)
[31](#assign-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2386)
*Effects*: Assigns u.first to the first element andu.second to the second element[.](#assign-31.sentence-1)
[32](#assign-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2391)
*Returns*: *this[.](#assign-32.sentence-1)
[🔗](#lib:operator=,tuple__________)
`template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
`
[33](#assign-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2403)
*Constraints*:
- [(33.1)](#assign-33.1)
sizeof...(Types) is 2 and
- [(33.2)](#assign-33.2)
is_assignable_v<T0&, U1> is true, and
- [(33.3)](#assign-33.3)
is_assignable_v<T1&, U2> is true[.](#assign-33.sentence-1)
[34](#assign-34)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2411)
*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[.](#assign-34.sentence-2)
[35](#assign-35)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2417)
*Returns*: *this[.](#assign-35.sentence-1)
[🔗](#lib:operator=,tuple___________)
`template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&& u) const;
`
[36](#assign-36)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2428)
*Constraints*:
- [(36.1)](#assign-36.1)
sizeof...(Types) is 2,
- [(36.2)](#assign-36.2)
is_assignable_v<const T0&, U1> is true, and
- [(36.3)](#assign-36.3)
is_assignable_v<const T1&, U2> is true[.](#assign-36.sentence-1)
[37](#assign-37)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2439)
*Effects*: Assigns std::forward<U1>(u.first) to the first element and
std::forward<U2>(u.second) to the second element[.](#assign-37.sentence-2)
[38](#assign-38)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2444)
*Returns*: *this[.](#assign-38.sentence-1)
[🔗](#lib:operator=,tuple____________)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>
constexpr tuple& operator=(UTuple&& u);
`
[39](#assign-39)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2456)
*Constraints*:
- [(39.1)](#assign-39.1)
[*different-from*](range.utility.helpers#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<UTuple, tuple> ([[range.utility.helpers]](range.utility.helpers "25.5.2Helper concepts"))
is true,
- [(39.2)](#assign-39.2)
remove_cvref_t<UTuple> is not a specialization of ranges::subrange,
- [(39.3)](#assign-39.3)
sizeof...(Types) equals tuple_size_v<remove_cvref_t<UTuple>>, and
- [(39.4)](#assign-39.4)
is_assignable_v<Ti&, decltype(get<i>(std::forward<UTuple>(u)))> is true for all i[.](#assign-39.sentence-1)
[40](#assign-40)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2476)
*Effects*: For all i, assigns get<i>(std::forward<UTuple>(u)) to get<i>(*this)[.](#assign-40.sentence-1)
[41](#assign-41)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2481)
*Returns*: *this[.](#assign-41.sentence-1)
[🔗](#lib:operator=,tuple_____________)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>
constexpr const tuple& operator=(UTuple&& u) const;
`
[42](#assign-42)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2493)
*Constraints*:
- [(42.1)](#assign-42.1)
[*different-from*](range.utility.helpers#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<UTuple, tuple> ([[range.utility.helpers]](range.utility.helpers "25.5.2Helper concepts"))
is true,
- [(42.2)](#assign-42.2)
remove_cvref_t<UTuple> is not a specialization of ranges::subrange,
- [(42.3)](#assign-42.3)
sizeof...(Types) equals tuple_size_v<remove_cvref_t<UTuple>>, and
- [(42.4)](#assign-42.4)
is_assignable_v<const Ti&, decltype(get<i>(std::forward<UTuple>(u)))> is true for all i[.](#assign-42.sentence-1)
[43](#assign-43)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2513)
*Effects*: For all i, assignsget<i>(std::forward<UTuple>(u)) to get<i>(*this)[.](#assign-43.sentence-1)
[44](#assign-44)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2518)
*Returns*: *this[.](#assign-44.sentence-1)
#### [22.4.4.4](#swap) swap [[tuple.swap]](tuple.swap)
[🔗](#lib:swap,tuple)
`constexpr void swap(tuple& rhs) noexcept(see below);
constexpr void swap(const tuple& rhs) const noexcept(see below);
`
[1](#swap-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2532)
Let i be in the range [0, sizeof...(Types)) in order[.](#swap-1.sentence-1)
[2](#swap-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2535)
*Mandates*:
- [(2.1)](#swap-2.1)
For the first overload,(is_swappable_v<Types> && ...) is true[.](#swap-2.1.sentence-1)
- [(2.2)](#swap-2.2)
For the second overload,(is_swappable_v<const Types> && ...) is true[.](#swap-2.2.sentence-1)
[3](#swap-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2546)
*Preconditions*: For all i, get<i>(*this) is swappable with ([[swappable.requirements]](swappable.requirements "16.4.4.3Swappable requirements")) get<i>(rhs)[.](#swap-3.sentence-1)
[4](#swap-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2550)
*Effects*: For each i, calls swap for get<i>(*this) and get<i>(rhs)[.](#swap-4.sentence-1)
[5](#swap-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2554)
*Throws*: Nothing unless one of the element-wise swap calls throws an exception[.](#swap-5.sentence-1)
[6](#swap-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2558)
*Remarks*: The exception specification is equivalent to
- [(6.1)](#swap-6.1)
(is_nothrow_swappable_v<Types> && ...) for the first overload and
- [(6.2)](#swap-6.2)
(is_nothrow_swappable_v<const Types> && ...) for the second overload[.](#swap-6.sentence-1)
### [22.4.5](#creation) Tuple creation functions [[tuple.creation]](tuple.creation)
[🔗](#lib:make_tuple)
`template<class... TTypes>
constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&... t);
`
[1](#creation-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2579)
*Returns*: tuple<unwrap_ref_decay_t<TTypes>...>(std::forward<TTypes>(t)...)[.](#creation-1.sentence-1)
[2](#creation-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2583)
[*Example [1](#creation-example-1)*:
int i; float j;
make_tuple(1, ref(i), cref(j)); creates a tuple of type tuple<int, int&, const float&>[.](#creation-2.sentence-1)
— *end example*]
[🔗](#lib:forward_as_tuple)
`template<class... TTypes>
constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&... t) noexcept;
`
[3](#creation-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2601)
*Effects*: Constructs a tuple of references to the arguments in t suitable
for forwarding as arguments to a function[.](#creation-3.sentence-1)
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)[.](#creation-3.sentence-2)
[4](#creation-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2609)
*Returns*: tuple<TTypes&&...>(std::forward<TTypes>(t)...)[.](#creation-4.sentence-1)
[🔗](#lib:tie)
`template<class... TTypes>
constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;
`
[5](#creation-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2623)
*Returns*: tuple<TTypes&...>(t...)[.](#creation-5.sentence-1)
[6](#creation-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2627)
[*Example [2](#creation-example-2)*:
tie functions allow one to create tuples that unpack
tuples into variables[.](#creation-6.sentence-1)
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++");// i == 42, s == "C++"
— *end example*]
[🔗](#lib:tuple_cat)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")... Tuples>
constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
`
[7](#creation-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2647)
Let n be sizeof...(Tuples)[.](#creation-7.sentence-1)
For every integer 0≤i<n:
- [(7.1)](#creation-7.1)
Let Ti be the ith type in Tuples[.](#creation-7.1.sentence-1)
- [(7.2)](#creation-7.2)
Let Ui be remove_cvref_t<Ti>[.](#creation-7.2.sentence-1)
- [(7.3)](#creation-7.3)
Let tpi be the ith element
in the function parameter pack tpls[.](#creation-7.3.sentence-1)
- [(7.4)](#creation-7.4)
Let Si be tuple_size_v<Ui>[.](#creation-7.4.sentence-1)
- [(7.5)](#creation-7.5)
Let Eki be tuple_element_t<k, Ui>[.](#creation-7.5.sentence-1)
- [(7.6)](#creation-7.6)
Let eki be get<k>(std::forward<Ti>(tpi))[.](#creation-7.6.sentence-1)
- [(7.7)](#creation-7.7)
Let Elemsi be a pack of the types E0i,…,ESi−1i[.](#creation-7.7.sentence-1)
- [(7.8)](#creation-7.8)
Let elemsi be a pack of the expressions e0i,…,eSi−1i[.](#creation-7.8.sentence-1)
The types in CTypes are equal to the ordered sequence of
the expanded packs of typesElems0..., Elems1..., …, Elemsn−1...[.](#creation-7.sentence-3)
Let celems be the ordered sequence of
the expanded packs of expressionselems0..., …, elemsn−1...[.](#creation-7.sentence-4)
[8](#creation-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2676)
*Mandates*: (is_constructible_v<CTypes, decltype(celems)> && ...) is true[.](#creation-8.sentence-1)
[9](#creation-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2680)
*Returns*: tuple<CTypes...>(celems...)[.](#creation-9.sentence-1)
### [22.4.6](#apply) Calling a function with a tuple of arguments [[tuple.apply]](tuple.apply)
[🔗](#lib:apply)
`template<class F, [tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") Tuple>
constexpr apply_result_t<F, Tuple> apply(F&& f, Tuple&& t)
noexcept(is_nothrow_applicable_v<F, Tuple>);
`
[1](#apply-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2695)
*Effects*: Given the exposition-only function template:namespace std {template<class F, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") Tuple, size_t... I>constexpr decltype(auto) *apply-impl*(F&& f, Tuple&& t, index_sequence<I...>) {// *exposition only*return *INVOKE*(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...); // see [[func.require]](func.require "22.10.4Requirements")}}
Equivalent to:return *apply-impl*(std::forward<F>(f), std::forward<Tuple>(t),
make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
[🔗](#lib:make_from_tuple)
`template<class T, [tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") Tuple>
constexpr T make_from_tuple(Tuple&& t);
`
[2](#apply-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2721)
*Mandates*: If tuple_size_v<remove_reference_t<Tuple>> is 1,
thenreference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))> is false[.](#apply-2.sentence-1)
[3](#apply-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2728)
*Effects*: Given the exposition-only function template:namespace std {template<class T, [*tuple-like*](#concept:tuple-like "22.4.3Concept tuple-like[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...>) { // *exposition only*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](#apply-note-1)*:
The type of T must be supplied
as an explicit template parameter,
as it cannot be deduced from the argument list[.](#apply-3.sentence-2)
— *end note*]
### [22.4.7](#helper) Tuple helper classes [[tuple.helper]](tuple.helper)
[🔗](#lib:tuple_size,in_general)
`template<class T> struct tuple_size;
`
[1](#helper-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2761)
Except where specified otherwise,
all specializations of tuple_size meet the[*Cpp17UnaryTypeTrait*](meta.rqmts#:Cpp17UnaryTypeTrait "21.3.2Requirements[meta.rqmts]") requirements ([[meta.rqmts]](meta.rqmts "21.3.2Requirements")) with a
base characteristic of integral_constant<size_t, N> for some N[.](#helper-1.sentence-1)
[🔗](#lib:tuple_size)
`template<class... Types>
struct tuple_size<tuple<Types...>> : integral_constant<size_t, sizeof...(Types)> { };
`
[🔗](#lib:tuple_element)
`template<size_t I, class... Types>
struct tuple_element<I, tuple<Types...>> {
using type = TI;
};
`
[2](#helper-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2784)
*Mandates*: I < sizeof...(Types)[.](#helper-2.sentence-1)
[3](#helper-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2788)
*Type*: TI is the
type of the Ith element of Types,
where indexing is zero-based[.](#helper-3.sentence-1)
[🔗](#lib:tuple_size_)
`template<class T> struct tuple_size<const T>;
`
[4](#helper-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2801)
Let TS denote tuple_size<T> of the cv-unqualified type T[.](#helper-4.sentence-1)
If the expression TS::value is well-formed
when treated as an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3Context dependence[expr.context]"), then
each specialization of the template meets the [*Cpp17UnaryTypeTrait*](meta.rqmts#:Cpp17UnaryTypeTrait "21.3.2Requirements[meta.rqmts]") requirements ([[meta.rqmts]](meta.rqmts "21.3.2Requirements"))
with a base characteristic ofintegral_constant<size_t, TS::value>
Otherwise, it has no member value[.](#helper-4.sentence-3)
[5](#helper-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2812)
Access checking is performed as if in a context
unrelated to TS and T[.](#helper-5.sentence-1)
Only the validity of the immediate context of the expression is considered[.](#helper-5.sentence-2)
[*Note [1](#helper-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[.](#helper-5.sentence-3)
Such side effects are not in the “immediate context” and
can result in the program being ill-formed[.](#helper-5.sentence-4)
— *end note*]
[6](#helper-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2824)
In addition to being available via inclusion of the [<tuple>](#header:%3ctuple%3e "22.4.2Header <tuple> synopsis[tuple.syn]") header,
the template is available
when any of the headers[<array>](array.syn#header:%3carray%3e "23.3.2Header <array> synopsis[array.syn]"),[<ranges>](ranges.syn#header:%3cranges%3e "25.2Header <ranges> synopsis[ranges.syn]"), or[<utility>](utility.syn#header:%3cutility%3e "22.2.1Header <utility> synopsis[utility.syn]") are included[.](#helper-6.sentence-1)
[🔗](#lib:tuple_element_)
`template<size_t I, class T> struct tuple_element<I, const T>;
`
[7](#helper-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2840)
Let TE denote tuple_element_t<I, T> of the cv-unqualified type T[.](#helper-7.sentence-1)
Then
each specialization of the template meets the [*Cpp17TransformationTrait*](meta.rqmts#:Cpp17TransformationTrait "21.3.2Requirements[meta.rqmts]") requirements ([[meta.rqmts]](meta.rqmts "21.3.2Requirements"))
with a member typedef type that names the type add_const_t<TE>[.](#helper-7.sentence-2)
[8](#helper-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2845)
In addition to being available via inclusion of the [<tuple>](#header:%3ctuple%3e "22.4.2Header <tuple> synopsis[tuple.syn]") header,
the template is available
when any of the headers[<array>](array.syn#header:%3carray%3e "23.3.2Header <array> synopsis[array.syn]"),[<ranges>](ranges.syn#header:%3cranges%3e "25.2Header <ranges> synopsis[ranges.syn]"), or[<utility>](utility.syn#header:%3cutility%3e "22.2.1Header <utility> synopsis[utility.syn]") are included[.](#helper-8.sentence-1)
### [22.4.8](#elem) Element access [[tuple.elem]](tuple.elem)
[🔗](#lib:get,tuple)
`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;
`
[1](#elem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2873)
*Mandates*: I < sizeof...(Types)[.](#elem-1.sentence-1)
[2](#elem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2877)
*Returns*: A reference to the Ith element of t, where
indexing is zero-based[.](#elem-2.sentence-1)
[3](#elem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2882)
[*Note [1](#elem-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&&[.](#elem-3.sentence-1)
However, if the element type is a non-reference type T,
the return type is T&&[.](#elem-3.sentence-2)
— *end note*]
[4](#elem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2891)
[*Note [2](#elem-note-2)*:
Constness is shallow[.](#elem-4.sentence-1)
For the overload marked #2,
if a type T in Types is some reference type X&,
the return type is X&, not const X&[.](#elem-4.sentence-2)
However, if the element type is a non-reference type T,
the return type is const T&[.](#elem-4.sentence-3)
This is consistent with how constness is defined to work
for non-static data members of reference type[.](#elem-4.sentence-4)
— *end note*]
[🔗](#lib:get,tuple_)
`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;
`
[5](#elem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2917)
*Mandates*: The type T occurs exactly once in Types[.](#elem-5.sentence-1)
[6](#elem-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2921)
*Returns*: A reference to the element of t corresponding to the typeT in Types[.](#elem-6.sentence-1)
[7](#elem-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2926)
[*Example [1](#elem-example-1)*: const tuple<int, const int, double, double> t(1, 2, 3.4, 5.6);const int& i1 = get<int>(t); // OK, i1 has value 1const int& i2 = get<const int>(t); // OK, i2 has value 2const double& d = get<double>(t); // error: type double is not unique within t — *end example*]
[8](#elem-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2937)
[*Note [3](#elem-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[.](#elem-8.sentence-1)
— *end note*]
### [22.4.9](#rel) Relational operators [[tuple.rel]](tuple.rel)
[🔗](#lib:operator==,tuple)
`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.3Concept tuple-like[tuple.like]") UTuple>
constexpr bool operator==(const tuple<TTypes...>& t, const UTuple& u);
`
[1](#rel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2957)
For the first overload let UTuple be tuple<UTypes...>[.](#rel-1.sentence-1)
[2](#rel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2960)
*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*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]")[.](#rel-2.sentence-1)
sizeof...(TTypes) equalstuple_size_v<UTuple>[.](#rel-2.sentence-2)
[3](#rel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2969)
*Returns*: true if get<i>(t) == get<i>(u) for alli, otherwise false[.](#rel-3.sentence-1)
[*Note [1](#rel-note-1)*:
If sizeof...(TTypes) equals zero, returns true[.](#rel-3.sentence-2)
— *end note*]
[4](#rel-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L2977)
*Remarks*:
- [(4.1)](#rel-4.1)
The elementary comparisons are performed in order from the
zeroth index upwards[.](#rel-4.1.sentence-1)
No comparisons or element accesses are
performed after the first equality comparison that evaluates tofalse[.](#rel-4.1.sentence-2)
- [(4.2)](#rel-4.2)
The second overload is to be found via argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup")) only[.](#rel-4.2.sentence-1)
[🔗](#lib:operator%3c=%3e,tuple)
`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.3Concept tuple-like[tuple.like]") UTuple>
constexpr common_comparison_category_t<synth-three-way-result<TTypes, Elems>...>
operator<=>(const tuple<TTypes...>& t, const UTuple& u);
`
[5](#rel-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3001)
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>[.](#rel-5.sentence-1)
[6](#rel-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3007)
*Effects*: Performs a lexicographical comparison between t and u[.](#rel-6.sentence-1)
If sizeof...(TTypes) equals zero,
returns strong_ordering::equal[.](#rel-6.sentence-2)
Otherwise, equivalent to:if (auto c = *synth-three-way*(get<0>(t), get<0>(u)); c != 0) return c;return ttail <=> utail; where rtail for some r is a tuple containing all but the first element of r[.](#rel-6.sentence-3)
[7](#rel-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3020)
*Remarks*: The second overload is to be found via argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup")) only[.](#rel-7.sentence-1)
[8](#rel-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3025)
[*Note [2](#rel-note-2)*:
The above definition does not require ttail (or utail) to be constructed[.](#rel-8.sentence-1)
It might not
even be possible, as t and u are not required to be copy
constructible[.](#rel-8.sentence-2)
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[.](#rel-8.sentence-3)
— *end note*]
### [22.4.10](#common.ref) common_reference related specializations [[tuple.common.ref]](tuple.common.ref)
[1](#common.ref-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3037)
In the descriptions that follow:
- [(1.1)](#common.ref-1.1)
Let TTypes be a pack formed by
the sequence of tuple_element_t<i, TTuple> for every integer 0≤i<tuple_size_v<TTuple>[.](#common.ref-1.1.sentence-1)
- [(1.2)](#common.ref-1.2)
Let UTypes be a pack formed by
the sequence of tuple_element_t<i, UTuple> for every integer 0≤i<tuple_size_v<UTuple>[.](#common.ref-1.2.sentence-1)
[🔗](#lib:basic_common_reference,tuple)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") TTuple, [tuple-like](#concept:tuple-like "22.4.3Concept 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;
};
`
[2](#common.ref-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3061)
*Constraints*:
- [(2.1)](#common.ref-2.1)
TTuple is a specialization of tuple orUTuple is a specialization of tuple[.](#common.ref-2.1.sentence-1)
- [(2.2)](#common.ref-2.2)
is_same_v<TTuple, decay_t<TTuple>> is true[.](#common.ref-2.2.sentence-1)
- [(2.3)](#common.ref-2.3)
is_same_v<UTuple, decay_t<UTuple>> is true[.](#common.ref-2.3.sentence-1)
- [(2.4)](#common.ref-2.4)
tuple_size_v<TTuple> equals tuple_size_v<UTuple>[.](#common.ref-2.4.sentence-1)
- [(2.5)](#common.ref-2.5)
tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...> denotes a type[.](#common.ref-2.5.sentence-1)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") type denotes the typetuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>[.](#common.ref-2.sentence-2)
[🔗](#lib:common_type,tuple)
`template<[tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") TTuple, [tuple-like](#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple>
struct common_type<TTuple, UTuple> {
using type = see below;
};
`
[3](#common.ref-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3090)
*Constraints*:
- [(3.1)](#common.ref-3.1)
TTuple is a specialization of tuple orUTuple is a specialization of tuple[.](#common.ref-3.1.sentence-1)
- [(3.2)](#common.ref-3.2)
is_same_v<TTuple, decay_t<TTuple>> is true[.](#common.ref-3.2.sentence-1)
- [(3.3)](#common.ref-3.3)
is_same_v<UTuple, decay_t<UTuple>> is true[.](#common.ref-3.3.sentence-1)
- [(3.4)](#common.ref-3.4)
tuple_size_v<TTuple> equals tuple_size_v<UTuple>[.](#common.ref-3.4.sentence-1)
- [(3.5)](#common.ref-3.5)
tuple<common_type_t<TTypes, UTypes>...> denotes a type[.](#common.ref-3.5.sentence-1)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") type denotes the typetuple<common_type_t<TTypes, UTypes>...>[.](#common.ref-3.sentence-2)
### [22.4.11](#traits) Tuple traits [[tuple.traits]](tuple.traits)
[🔗](#lib:uses_allocator%3ctuple%3e)
`template<class... Types, class Alloc>
struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
`
[1](#traits-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3118)
*Preconditions*: Alloc meets
the [*Cpp17Allocator*](allocator.requirements.general#:Cpp17Allocator "16.4.4.6.1General[allocator.requirements.general]") requirements ([[allocator.requirements.general]](allocator.requirements.general "16.4.4.6.1General"))[.](#traits-1.sentence-1)
[2](#traits-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3123)
[*Note [1](#traits-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[.](#traits-2.sentence-1)
— *end note*]
### [22.4.12](#special) Tuple specialized algorithms [[tuple.special]](tuple.special)
[🔗](#lib:swap,tuple_)
`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);
`
[1](#special-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3142)
*Constraints*:
- [(1.1)](#special-1.1)
For the first overload,(is_swappable_v<Types> && ...) is true[.](#special-1.1.sentence-1)
- [(1.2)](#special-1.2)
For the second overload,(is_swappable_v<const Types> && ...) is true[.](#special-1.2.sentence-1)
[2](#special-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3153)
*Effects*: As if by x.swap(y)[.](#special-2.sentence-1)
[3](#special-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L3157)
*Remarks*: The exception specification is equivalent to:noexcept(x.swap(y))