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

36 KiB
Raw Blame History

[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...>;}

1

#

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]

1

#

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.

2

#

For each tuple constructor, an exception is thrown only if the construction of one of the types in Types throws an exception.

3

#

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.

4

#

If is_trivially_destructible_v is true for all Ti, then the destructor of tuple is trivial.

5

#

The default constructor of tuple<> is trivial.

🔗

constexpr explicit(see below) tuple();

6

#

Constraints: is_default_constructible_v is true for all i.

7

#

Effects: Value-initializes each element.

8

#

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&...);

9

#

Constraints: sizeof...(Types) ≥ 1 andis_copy_constructible_v is true for all i.

10

#

Effects: Initializes each element with the value of the corresponding parameter.

11

#

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);

12

#

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.

13

#

Constraints:

sizeof...(Types) equals sizeof...(UTypes),

sizeof...(Types) ≥ 1, and

conjunction_v<disambiguating-constraint, is_constructible<Types, UTypes>...> is
true.

14

#

Effects: Initializes the elements in the tuple with the corresponding value in std::forward(u).

15

#

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;

16

#

Mandates: is_copy_constructible_v is true for all i.

17

#

Effects: Initializes each element of *this with the corresponding element of u.

🔗

tuple(tuple&& u) = default;

18

#

Constraints: is_move_constructible_v is true for all i.

19

#

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);

20

#

Let I be the pack 0, 1, …, (sizeof...(Types) - 1).

Let FWD(u) be static_cast<decltype(u)>(u).

21

#

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.

22

#

Effects: For all i, initializes the ith element of *this with get(FWD(u)).

23

#

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);

24

#

Let FWD(u) be static_cast<decltype(u)>(u).

25

#

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.

26

#

Effects: Initializes the first element with get<0>(FWD(u)) and the second element with get<1>(FWD(u)).

27

#

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.3Concept tuple-like[tuple.like]") UTuple> constexpr explicit(see below) tuple(UTuple&& u);

28

#

Let I be the pack 0, 1, …, (sizeof...(Types) - 1).

29

#

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.

30

#

Effects: For all i, initializes the ith element of *this withget(std::forward(u)).

31

#

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.3Concept tuple-like[tuple.like]") UTuple> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTuple&&);

32

#

Preconditions: Alloc meets the Cpp17Allocator requirements ([allocator.requirements.general]).

33

#

Effects: Equivalent to the preceding constructors except that each element is constructed withuses-allocator construction.

22.4.4.3 Assignment [tuple.assign]

1

#

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);

2

#

Effects: Assigns each element of u to the corresponding element of *this.

3

#

Returns: *this.

4

#

Remarks: This operator is defined as deleted unlessis_copy_assignable_v is true for all i.

🔗

constexpr const tuple& operator=(const tuple& u) const;

5

#

Constraints: (is_copy_assignable_v && ...) is true.

6

#

Effects: Assigns each element of u to the corresponding element of *this.

7

#

Returns: *this.

🔗

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

8

#

Constraints: is_move_assignable_v is true for all i.

9

#

Effects: For all i, assigns std::forward(get(u)) toget(*this).

10

#

Returns: *this.

11

#

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;

12

#

Constraints: (is_assignable_v<const Types&, Types> && ...) is true.

13

#

Effects: For all i, assigns std::forward(get(u)) to get(*this).

14

#

Returns: *this.

🔗

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

15

#

Constraints:

sizeof...(Types) equals sizeof...(UTypes) and

is_assignable_v<Ti&, const Ui&> is true for all i.

16

#

Effects: Assigns each element of u to the corresponding element of *this.

17

#

Returns: *this.

🔗

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

18

#

Constraints:

sizeof...(Types) equals sizeof...(UTypes) and

(is_assignable_v<const Types&, const UTypes&> && ...) is true.

19

#

Effects: Assigns each element of u to the corresponding element of *this.

20

#

Returns: *this.

🔗

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

21

#

Constraints:

sizeof...(Types) equals sizeof...(UTypes) and

is_assignable_v<Ti&, Ui> is true for all i.

22

#

Effects: For all i, assigns std::forward(get(u)) toget(*this).

23

#

Returns: *this.

🔗

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

24

#

Constraints:

sizeof...(Types) equals sizeof...(UTypes) and

(is_assignable_v<const Types&, UTypes> && ...) is true.

25

#

Effects: For all i, assigns std::forward(get(u)) to get(*this).

26

#

Returns: *this.

🔗

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

27

#

Constraints:

sizeof...(Types) is 2 and

is_assignable_v<T0&, const U1&> is true, and

is_assignable_v<T1&, const U2&> is true.

28

#

Effects: Assigns u.first to the first element of *this and u.second to the second element of *this.

29

#

Returns: *this.

🔗

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

30

#

Constraints:

sizeof...(Types) is 2,

is_assignable_v<const T0&, const U1&> is true, and

is_assignable_v<const T1&, const U2&> is true.

31

#

Effects: Assigns u.first to the first element andu.second to the second element.

32

#

Returns: *this.

🔗

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

33

#

Constraints:

sizeof...(Types) is 2 and

is_assignable_v<T0&, U1> is true, and

is_assignable_v<T1&, U2> is true.

34

#

Effects: Assigns std::forward(u.first) to the first element of *this and

std::forward(u.second) to the second element of *this.

35

#

Returns: *this.

🔗

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

36

#

Constraints:

sizeof...(Types) is 2,

is_assignable_v<const T0&, U1> is true, and

is_assignable_v<const T1&, U2> is true.

37

#

Effects: Assigns std::forward(u.first) to the first element and

std::forward(u.second) to the second element.

38

#

Returns: *this.

🔗

template<[tuple-like](tuple.like#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple> constexpr tuple& operator=(UTuple&& u);

39

#

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.

40

#

Effects: For all i, assigns get(std::forward(u)) to get(*this).

41

#

Returns: *this.

🔗

template<[tuple-like](tuple.like#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]") UTuple> constexpr const tuple& operator=(UTuple&& u) const;

42

#

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.

43

#

Effects: For all i, assignsget(std::forward(u)) to get(*this).

44

#

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);

1

#

Let i be in the range [0, sizeof...(Types)) in order.

2

#

Mandates:

  • (2.1)

    For the first overload,(is_swappable_v && ...) is true.

  • (2.2)

    For the second overload,(is_swappable_v && ...) is true.

3

#

Preconditions: For all i, get(*this) is swappable with ([swappable.requirements]) get(rhs).

4

#

Effects: For each i, calls swap for get(*this) and get(rhs).

5

#

Throws: Nothing unless one of the element-wise swap calls throws an exception.

6

#

Remarks: The exception specification is equivalent to

(is_nothrow_swappable_v && ...) for the first overload and

(is_nothrow_swappable_v && ...) for the second overload.