namespace std {
template <class... Types>
class tuple;
inline constexpr unspecified ignore;
template <class... TTypes>
constexpr tuple<VTypes...> make_tuple(TTypes&&...);
template <class... TTypes>
constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept;
template<class... TTypes>
constexpr tuple<TTypes&...> tie(TTypes&...) noexcept;
template <class... Tuples>
constexpr tuple<CTypes...> tuple_cat(Tuples&&...);
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t);
template <class T, class Tuple>
constexpr T make_from_tuple(Tuple&& t);
template <class T> class tuple_size; template <class T> class tuple_size<const T>;
template <class T> class tuple_size<volatile T>;
template <class T> class tuple_size<const volatile T>;
template <class... Types> class tuple_size<tuple<Types...>>;
template <size_t I, class T> class tuple_element; template <size_t I, class T> class tuple_element<I, const T>;
template <size_t I, class T> class tuple_element<I, volatile T>;
template <size_t I, class T> class tuple_element<I, const volatile T>;
template <size_t I, class... Types>
class tuple_element<I, tuple<Types...>>;
template <size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;
template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>&) noexcept;
template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&&) noexcept;
template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>&) noexcept;
template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&&) noexcept;
template <class T, class... Types>
constexpr T& get(tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr T&& get(tuple<Types...>&& t) noexcept;
template <class T, class... Types>
constexpr const T& get(const tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
template<class... TTypes, class... UTypes>
constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&);
template<class... TTypes, class... UTypes>
constexpr bool operator<(const tuple<TTypes...>&, const tuple<UTypes...>&);
template<class... TTypes, class... UTypes>
constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);
template<class... TTypes, class... UTypes>
constexpr bool operator>(const tuple<TTypes...>&, const tuple<UTypes...>&);
template<class... TTypes, class... UTypes>
constexpr bool operator<=(const tuple<TTypes...>&, const tuple<UTypes...>&);
template<class... TTypes, class... UTypes>
constexpr bool operator>=(const tuple<TTypes...>&, const tuple<UTypes...>&);
template <class... Types, class Alloc>
struct uses_allocator<tuple<Types...>, Alloc>;
template <class... Types>
void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
template <class T>
inline constexpr size_t tuple_size_v = tuple_size<T>::value;
}
namespace std {
template <class... Types>
class tuple {
public:
EXPLICIT constexpr tuple();
EXPLICIT constexpr tuple(const Types&...); template <class... UTypes>
EXPLICIT constexpr tuple(UTypes&&...);
tuple(const tuple&) = default;
tuple(tuple&&) = default;
template <class... UTypes>
EXPLICIT constexpr tuple(const tuple<UTypes...>&);
template <class... UTypes>
EXPLICIT constexpr tuple(tuple<UTypes...>&&);
template <class U1, class U2>
EXPLICIT constexpr tuple(const pair<U1, U2>&); template <class U1, class U2>
EXPLICIT constexpr tuple(pair<U1, U2>&&);
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a);
template <class Alloc>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, const tuple&);
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, tuple&&);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
tuple& operator=(const tuple&);
tuple& operator=(tuple&&) noexcept(see below);
template <class... UTypes>
tuple& operator=(const tuple<UTypes...>&);
template <class... UTypes>
tuple& operator=(tuple<UTypes...>&&);
template <class U1, class U2>
tuple& operator=(const pair<U1, U2>&); template <class U1, class U2>
tuple& operator=(pair<U1, U2>&&);
void swap(tuple&) noexcept(see below);
};
template<class... UTypes>
tuple(UTypes...) -> tuple<UTypes...>;
template<class T1, class T2>
tuple(pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>;
template<class Alloc, class T1, class T2>
tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>;
}
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, of
tuple shall be a constexpr function if and only if all
required element-wise initializations for copy and move, respectively,
would satisfy the requirements for a constexpr function
. The
defaulted move and copy constructor of
tuple<> shall be
constexpr functions
.The destructor of tuple shall be a trivial destructor if
(is_trivially_destructible_v<Types> && ...)
is
true.In the constructor 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
. EXPLICIT constexpr tuple();
Effects: Value-initializes each element
. Remarks:
This constructor shall not participate in overload resolution unless
is_default_constructible_v<> is
true for all
i. [
Note: This behavior can be implemented by a constructor template
with default template arguments
. —
end note ]
The constructor is explicit if and only if is not implicitly
default-constructible for at least one
i. [
Note: This behavior can be implemented with a trait that checks whether
a
const & can be initialized with
{}. —
end note ]
EXPLICIT constexpr tuple(const Types&...);
Effects: Initializes each element with the value of the
corresponding parameter
. Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) >= 1 and
is_copy_constructible_v<>
is
true for all
i. The constructor is explicit if and only if
is_convertible_v<const &, > is
false
for at least one
i.template <class... UTypes> EXPLICIT constexpr tuple(UTypes&&... u);
Effects: Initializes the elements in the tuple with the
corresponding value in
std::forward<UTypes>(u). Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) == sizeof...(UTypes) and
sizeof...(Types) >= 1 and
is_constructible_v<, &&>
is
true for all
i. The constructor is explicit if and only if
is_convertible_v<&&, > is
false
for at least one
i.tuple(const tuple& u) = default;
Requires: 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;
Requires: is_move_constructible_v<> is
true for all
i. Effects: For all
i, initializes the element of
*this with
std::forward<>(get<i>(u)). template <class... UTypes> EXPLICIT constexpr tuple(const tuple<UTypes...>& u);
Effects: Initializes each element of
*this
with the corresponding element of
u. Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) == sizeof...(UTypes) and
is_constructible_v<, const &> is true for all i, and
sizeof...(Types) != 1, or
(when
Types... expands to
T and
UTypes... expands to
U)
!is_convertible_v<const tuple<U>&, T> && !is_constructible_v<T, const tuple<U>&>
&& !is_same_v<T, U>
is
true.
The constructor is explicit if and only if
is_convertible_v<const &, > is
false
for at least one
i.template <class... UTypes> EXPLICIT constexpr tuple(tuple<UTypes...>&& u);
Effects: For all
i,
initializes the element of
*this with
std::forward<>(get<i>(u)). Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) == sizeof...(UTypes), and
is_constructible_v<, &&> is true for all i, and
sizeof...(Types) != 1, or
(when
Types... expands to
T and
UTypes... expands to
U)
!is_convertible_v<tuple<U>, T> && !is_constructible_v<T, tuple<U>> &&
!is_same_v<T, U>
is
true.
The constructor is explicit if and only if
is_convertible_v<&&, > is
false
for at least one
i.template <class U1, class U2> EXPLICIT constexpr tuple(const pair<U1, U2>& u);
Effects: Initializes the first element with
u.first and the
second element with
u.second. Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) == 2,
is_constructible_v<, const U1&> is
true and
is_constructible_v<, const U2&> is
true. The constructor is explicit if and only if
is_convertible_v<const U1&, > is
false or
is_convertible_v<const U2&, > is
false.template <class U1, class U2> EXPLICIT constexpr tuple(pair<U1, U2>&& u);
Effects: Initializes the first element with
std::forward<U1>(u.first) and the
second element with
std::forward<U2>(u.second). Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) == 2,
is_constructible_v<, U1&&> is
true and
is_constructible_v<, U2&&> is
true. The constructor is explicit if and only if
is_convertible_v<U1&&, > is
false or
is_convertible_v<U2&&, > is
false.template <class Alloc>
tuple(allocator_arg_t, const Alloc& a);
template <class Alloc>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, const tuple&);
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, tuple&&);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
Effects: Equivalent to the preceding constructors except that each element is constructed with
uses-allocator construction (
[allocator.uses.construction])
. 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
. tuple& operator=(const tuple& u);
Effects: Assigns each element of
u to the corresponding
element of
*this. Remarks: This operator shall be defined as deleted unless
is_copy_assignable_v<> is
true for all
i. tuple& operator=(tuple&& u) noexcept(see below);
Effects: For all
i, assigns
std::forward<>(get<i>(u)) to
get<i>(*this). Remarks: This operator shall be defined as deleted unless
is_move_assignable_v<> is
true for all
i. Remarks: The expression inside noexcept is equivalent to the logical and of the
following expressions:
is_nothrow_move_assignable_v<>
where is the type in
Types.template <class... UTypes> tuple& operator=(const tuple<UTypes...>& u);
Effects: Assigns each element of
u to the corresponding element
of
*this. Remarks: This operator shall not participate in overload resolution unless
sizeof...(Types) == sizeof...(UTypes) and
is_assignable_v<&, const &> is
true for all
i. template <class... UTypes> tuple& operator=(tuple<UTypes...>&& u);
Effects: For all
i, assigns
std::forward<>(get<i>(u)) to
get<i>(*this). Remarks: This operator shall not participate in overload resolution unless
is_assignable_v<&, &&> == true for all
i and
sizeof...(Types) == sizeof...(UTypes). template <class U1, class U2> tuple& operator=(const pair<U1, U2>& u);
Effects: Assigns
u.first to the first element of
*this
and
u.second to the second element of
*this. Remarks: This operator shall not participate in overload resolution unless
sizeof...(Types) == 2 and
is_assignable_v<&, const U1&> is
true for the first type in
Types and
is_assignable_v<&, const U2&> is
true for the
second type in
Types. template <class U1, class U2> tuple& operator=(pair<U1, U2>&& u);
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. Remarks:
This operator shall not participate in overload resolution unless
sizeof...(Types) == 2 and
is_assignable_v<&, U1&&> is
true for the first type in
Types and
is_assignable_v<&, U2&&> is
true for the second
type in
Types. void swap(tuple& rhs) noexcept(see below);
Effects: Calls
swap for each element in
*this and its
corresponding element in
rhs. Remarks: The expression inside noexcept is equivalent to the logical
and of the following expressions:
where is the type in
Types.Throws: Nothing unless one of the element-wise
swap calls throws an exception
. In the function descriptions that follow, the members of a parameter pack
XTypes
are denoted by
X for
i in
[0, sizeof...(XTypes)) in
order, where indexing is zero-based
. template<class... TTypes>
constexpr tuple<VTypes...> make_tuple(TTypes&&... t);
The pack
VTypes is defined as follows
. Let
U be
decay_t<T> for each
T in
TTypes. If
U is a specialization of
reference_wrapper, then
V in
VTypes is
U::type&,
otherwise
V is
U.Returns: tuple<VTypes...>(std::forward<TTypes>(t)...). [
Example:
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 variables, 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...). When an
argument in
t is
ignore, assigning
any value to the corresponding tuple element has no effect
.[
Example: 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 <class... Tuples>
constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
In the following paragraphs, let be the type in
Tuples,
be
remove_reference_t<T>, and be the
parameter in the function parameter pack
tpls, where all indexing is
zero-based
.Requires: For all
i, shall be the type
tuple<...>, where is the (possibly empty)
cv-qualifier-seq and is the parameter pack representing the element
types in
. For all
the following requirements shall be satisfied:
Remarks: The types in
CTypes shall be equal to the ordered
sequence of the extended types
..., ..., …, ...,
where
n is
equal to
sizeof...(Tuples). Let
... be the
ordered sequence of tuple elements of the resulting
tuple object
corresponding to the type sequence
.Returns: A
tuple object constructed by initializing the
type element in
... with
get<>(std::forward<>())
for each valid and each group in order
. [
Note: An implementation may support additional types in the parameter
pack
Tuples that support the
tuple-like protocol, such as
pair and
array. —
end note ]
23.5.3.5 Calling a function with a tuple of arguments [tuple.apply]
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t);
Effects:
Given the exposition-only function:
template <class F, class Tuple, size_t... I>
constexpr decltype(auto)
apply_impl(F&& f, Tuple&& t, index_sequence<I...>) { return INVOKE(std::forward<F>(f), std::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<decay_t<Tuple>>>{});
template <class T, class Tuple>
constexpr T make_from_tuple(Tuple&& t);
Effects:
Given the exposition-only function:
template <class T, class Tuple, size_t... I>
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>(forward<Tuple>(t),
make_index_sequence<tuple_size_v<decay_t<Tuple>>>{});
[
Note: The type of
T must be supplied
as an explicit template parameter,
as it cannot be deduced from the argument list
. —
end note ]
template <class T> struct tuple_size;
Remarks: All specializations of
tuple_size shall meet the
UnaryTypeTrait requirements (
[meta.rqmts]) with a
base characteristic of
integral_constant<size_t, N>
for some
N. template <class... Types>
class tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { };
template <size_t I, class... Types>
class tuple_element<I, tuple<Types...>> {
public:
using type = TI;
};
Requires: I < sizeof...(Types). The program is ill-formed if
I is out of bounds
.Type: TI is the
type of the
Ith element of
Types,
where indexing is zero-based
. template <class T> class tuple_size<const T>;
template <class T> class tuple_size<volatile T>;
template <class T> class tuple_size<const volatile T>;
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
of the three templates shall meet the
UnaryTypeTrait requirements (
[meta.rqmts])
with a base characteristic of
integral_constant<size_t, TS::value>
Otherwise, they shall have 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: 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
<tuple> header,
the three templates are available when either of the headers
<array> or
<utility> are included
.template <size_t I, class T> class tuple_element<I, const T>;
template <size_t I, class T> class tuple_element<I, volatile T>;
template <size_t I, class T> class tuple_element<I, const volatile T>;
Let
TE denote
tuple_element_t<I, T> of the
cv-unqualified type
T. Then
each of the three templates shall meet the
TransformationTrait
requirements (
[meta.rqmts]) with a member typedef
type that names the following
type:
for the first specialization, add_const_t<TE>,
for the second specialization, add_volatile_t<TE>, and
for the third specialization,
add_cv_t<TE>.
In addition to being available via inclusion of the
<tuple> header,
the three templates are available when either of the headers
<array> or
<utility> are included
.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; template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&
get(const tuple<Types...>& t) noexcept; template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&& t) noexcept;
Requires: I < sizeof...(Types). The program is ill-formed if
I is out of bounds
.Returns: A reference to the
Ith element of
t, where
indexing is zero-based
. [
Note: [Note A]
If a
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: [Note B]
Constness is shallow
. If a
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 member variables 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;
Requires: The type
T occurs exactly once in
Types.... Otherwise, the program is ill-formed
.Returns: A reference to the element of
t corresponding to the type
T in
Types.... [
Example:
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: 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 ]
template<class... TTypes, class... UTypes>
constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
Requires: For all
i,
where
0 <= i and
i < sizeof...(TTypes),
get<i>(t) == get<i>(u) is a valid expression
returning a type that is convertible to
bool. sizeof...(TTypes) ==
sizeof...(UTypes). Returns: true if
get<i>(t) == get<i>(u) for all
i, otherwise
false. For any two zero-length tuples
e and
f,
e == f returns
true.Effects: 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 to
false.template<class... TTypes, class... UTypes>
constexpr bool operator<(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
Requires: For all
i,
where
0 <= i and
i < sizeof...(TTypes), both
get<i>(t) < get<i>(u)
and
get<i>(u) < get<i>(t)
are valid expressions returning types that are
convertible to
bool. sizeof...(TTypes) ==
sizeof...(UTypes). Returns: The result of a lexicographical comparison
between
t and
u. The result is defined
as:
(bool)(get<0>(t) < get<0>(u)) ||
(!(bool)(get<0>(u) < get<0>(t)) && t <
u), where
r for some
tuple
r is a tuple containing all but the first element
of
r. For any two zero-length tuples
e
and
f,
e < f returns
false.template<class... TTypes, class... UTypes>
constexpr bool operator!=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
template<class... TTypes, class... UTypes>
constexpr bool operator>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
template<class... TTypes, class... UTypes>
constexpr bool operator<=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
template<class... TTypes, class... UTypes>
constexpr bool operator>=(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
[
Note: The above definitions for comparison functions
do not require
t
(or
u) to be constructed
. It may not
even be possible, as
t and
u are not required to be copy
constructible
. Also, all comparison functions are short circuited;
they do not perform element accesses beyond what is required to determine the
result of the comparison
. —
end note ]
template <class... Types, class Alloc>
struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
[
Note: Specialization of this trait informs other library components that
tuple can be constructed with an allocator, even though it does not have
a nested
allocator_type. —
end note ]
template <class... Types>
void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
Remarks: This function shall not participate in overload resolution
unless
is_swappable_v<> is
true
for all
i, where
. The expression inside noexcept is equivalent to:
Effects: As if by
x.swap(y).