36 KiB
[tuple.tuple]
22 General utilities library [utilities]
22.4 Tuples [tuple]
22.4.4 Class template tuple [tuple.tuple]
22.4.4.1 General [tuple.tuple.general]
namespace std {template<class... Types>class tuple {public:// [tuple.cnstr], 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 UTuple>constexpr explicit(see below) tuple(UTuple&&); // allocator-extended constructorstemplateconstexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a); templateconstexpr 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&&...); templateconstexpr tuple(allocator_arg_t, const Alloc& a, const tuple&); templateconstexpr 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&&); // [tuple.assign], 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 UTuple>constexpr tuple& operator=(UTuple&&); template<tuple-like UTuple>constexpr const tuple& operator=(UTuple&&) const; // [tuple.swap], 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...>;}
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, Ti be the ith type in Types, andUi be the ith 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 Ti, 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 true if and only if Ti 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 Ti& 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(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 ith element of *this withstd::forward(get(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(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 ith element of *this with get(FWD(u)).
Remarks: The expression inside explicit is equivalent to:!(is_convertible_v<decltype(get(FWD(u))), Types> && ...)
The constructor is defined as deleted if(reference_constructs_from_temporary_v<Types, decltype(get(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<T0, decltype(get<0>(FWD(u)))> is true, and
is_constructible_v<T1, 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))), 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.
template<[tuple-like](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 is not a specialization of ranges::subrange,
sizeof...(Types) equals tuple_size_v<remove_cvref_t>,
(is_constructible_v<Types, decltype(get(std::forward(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 ith element of *this withget(std::forward(u)).
Remarks: The expression inside explicit is equivalent to:!(is_convertible_v<decltype(get(std::forward(u))), Types> && ...)
The constructor is defined as deleted if(reference_constructs_from_temporary_v<Types, decltype(get(std::forward(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](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&&);
Preconditions: Alloc meets the Cpp17Allocator requirements ([allocator.requirements.general]).
Effects: Equivalent to the preceding constructors except that each element is constructed withuses-allocator construction.
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, 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.
constexpr tuple& operator=(const tuple& u);
Effects: Assigns each element of u to the corresponding element of *this.
Returns: *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 && ...) is true.
Effects: Assigns each element of u to the corresponding element of *this.
Returns: *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(u)) toget(*this).
Returns: *this.
Remarks: The exception specification is equivalent to the logical and of the following expressions:is_nothrow_move_assignable_v where Ti is the ith 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(get(u)) to get(*this).
Returns: *this.
template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
Constraints:
sizeof...(Types) equals sizeof...(UTypes) and
is_assignable_v<Ti&, const Ui&> is true for all i.
Effects: Assigns each element of u to the corresponding element of *this.
Returns: *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.
Returns: *this.
template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
Constraints:
sizeof...(Types) equals sizeof...(UTypes) and
is_assignable_v<Ti&, Ui> is true for all i.
Effects: For all i, assigns std::forward(get(u)) toget(*this).
Returns: *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(get(u)) to get(*this).
Returns: *this.
template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
Constraints:
sizeof...(Types) is 2 and
is_assignable_v<T0&, const U1&> is true, and
is_assignable_v<T1&, const U2&> is true.
Effects: Assigns u.first to the first element of *this and u.second to the second element of *this.
Returns: *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 T0&, const U1&> is true, and
is_assignable_v<const T1&, const U2&> is true.
Effects: Assigns u.first to the first element andu.second to the second element.
Returns: *this.
template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
Constraints:
sizeof...(Types) is 2 and
is_assignable_v<T0&, U1> is true, and
is_assignable_v<T1&, U2> is true.
Effects: Assigns std::forward(u.first) to the first element of *this and
std::forward(u.second) to the second element of *this.
Returns: *this.
template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&& u) const;
Constraints:
sizeof...(Types) is 2,
is_assignable_v<const T0&, U1> is true, and
is_assignable_v<const T1&, U2> is true.
Effects: Assigns std::forward(u.first) to the first element and
std::forward(u.second) to the second element.
Returns: *this.
template<[tuple-like](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 is not a specialization of ranges::subrange,
sizeof...(Types) equals tuple_size_v<remove_cvref_t>, and
is_assignable_v<Ti&, decltype(get(std::forward(u)))> is true for all i.
Effects: For all i, assigns get(std::forward(u)) to get(*this).
Returns: *this.
template<[tuple-like](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 is not a specialization of ranges::subrange,
sizeof...(Types) equals tuple_size_v<remove_cvref_t>, and
is_assignable_v<const Ti&, decltype(get(std::forward(u)))> is true for all i.
Effects: For all i, assignsget(std::forward(u)) to get(*this).
Returns: *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 && ...) is true.
-
For the second overload,(is_swappable_v && ...) is true.
Preconditions: For all i, get(*this) is swappable with ([swappable.requirements]) get(rhs).
Effects: For each i, calls swap for get(*this) and get(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 && ...) for the first overload and
(is_nothrow_swappable_v && ...) for the second overload.