20 General utilities library [utilities]

20.4 Pairs [pairs]

20.4.1 In general [pairs.general]

The library provides a template for heterogeneous pairs of values. The library also provides a matching function template to simplify their construction and several templates that provide access to pair objects as if they were tuple objects (see [tuple.helper] and [tuple.elem]).

20.4.2 Class template pair [pairs.pair]

// defined in header <utility>

namespace std {
  template <class T1, class T2>
  struct pair {
    using first_type  = T1;
    using second_type = T2;

    T1 first;
    T2 second;
    pair(const pair&) = default;
    pair(pair&&) = default;
    EXPLICIT constexpr pair();
    EXPLICIT constexpr pair(const T1& x, const T2& y);
    template<class U, class V> EXPLICIT constexpr pair(U&& x, V&& y);
    template<class U, class V> EXPLICIT constexpr pair(const pair<U, V>& p);
    template<class U, class V> EXPLICIT constexpr pair(pair<U, V>&& p);
    template <class... Args1, class... Args2>
      pair(piecewise_construct_t,
           tuple<Args1...> first_args, tuple<Args2...> second_args);

    pair& operator=(const pair& p);
    template<class U, class V> pair& operator=(const pair<U, V>& p);
    pair& operator=(pair&& p) noexcept(see below);
    template<class U, class V> pair& operator=(pair<U, V>&& p);

    void swap(pair& p) noexcept(see below);
  };
}

Constructors and member functions of pair shall not throw exceptions unless one of the element-wise operations specified to be called for that operation throws an exception.

The defaulted move and copy constructor, respectively, of pair 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.

EXPLICIT constexpr pair();

Effects: Value-initializes first and second.

Remarks: This constructor shall not participate in overload resolution unless is_default_constructible_v<first_type> is true and is_default_constructible_v<second_type> is true. [ Note: This behavior can be implemented by a constructor template with default template arguments.  — end note ] The constructor is explicit if and only if either first_type or second_type is not implicitly default-constructible. [ Note: This behavior can be implemented with a trait that checks whether a const first_type& or a const second_type& can be initialized with {}.  — end note ]

EXPLICIT constexpr pair(const T1& x, const T2& y);

Effects: The constructor initializes first with x and second with y.

Remarks: This constructor shall not participate in overload resolution unless is_copy_constructible_v<first_type> is true and is_copy_constructible_v<second_type> is true. The constructor is explicit if and only if is_convertible_v<const first_type&, first_type> is false or is_convertible_v<const second_type&, second_type> is false.

template<class U, class V> EXPLICIT constexpr pair(U&& x, V&& y);

Effects: The constructor initializes first with std::forward<U>(x) and second with std::forward<V>(y).

Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<first_type, U&&> is true and is_constructible_v<second_type, V&&> is true. The constructor is explicit if and only if is_convertible_v<U&&, first_type> is false or is_convertible_v<V&&, second_type> is false.

template<class U, class V> EXPLICIT constexpr pair(const pair<U, V>& p);

Effects: The constructor initializes members from the corresponding members of the argument.

Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<first_type, const U&> is true and is_constructible_v<second_type, const V&> is true. The constructor is explicit if and only if is_convertible_v<const U&, first_type> is false or is_convertible_v<const V&, second_type> is false.

template<class U, class V> EXPLICIT constexpr pair(pair<U, V>&& p);

Effects: The constructor initializes first with std::forward<U>(p.first) and second with std::forward<V>(p.second).

Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<first_type, U&&> is true and is_constructible_v<second_type, V&&> is true. The constructor is explicit if and only if is_convertible_v<U&&, first_type> is false or is_convertible_v<V&&, second_type> is false.

template<class... Args1, class... Args2> pair(piecewise_construct_t, tuple<Args1...> first_args, tuple<Args2...> second_args);

Requires: is_constructible_v<first_type, Args1&&...> is true and is_constructible_v<second_type, Args2&&...> is true.

Effects: The constructor initializes first with arguments of types Args1... obtained by forwarding the elements of first_args and initializes second with arguments of types Args2... obtained by forwarding the elements of second_args. (Here, forwarding an element x of type U within a tuple object means calling std::forward<U>(x).) This form of construction, whereby constructor arguments for first and second are each provided in a separate tuple object, is called piecewise construction.

pair& operator=(const pair& p);

Remarks: This operator shall be defined as deleted unless is_copy_assignable_v<first_type> is true and is_copy_assignable_v<second_type> is true.

Effects: Assigns p.first to first and p.second to second.

Returns: *this.

template<class U, class V> pair& operator=(const pair<U, V>& p);

Remarks: This operator shall not participate in overload resolution unless is_assignable_v<first_type&, const U&> is true and is_assignable_v<second_type&, const V&> is true.

Effects: Assigns p.first to first and p.second to second.

Returns: *this.

pair& operator=(pair&& p) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

is_nothrow_move_assignable_v<T1> && is_nothrow_move_assignable_v<T2>

Remarks: This operator shall be defined as deleted unless is_move_assignable_v<first_type> is true and is_move_assignable_v<second_type> is true.

Effects: Assigns to first with std::forward<first_type>(p.first) and to second with
std::forward<second_type>(p.second).

Returns: *this.

template<class U, class V> pair& operator=(pair<U, V>&& p);

Remarks: This operator shall not participate in overload resolution unless is_assignable_v<first_type&, U&&> is true and is_assignable_v<second_type&, V&&> is true.

Effects: Assigns to first with std::forward<U>(p.first) and to second with
std::forward<V>(p.second).

Returns: *this.

void swap(pair& p) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

is_nothrow_swappable_v<first_type> &&
is_nothrow_swappable_v<second_type>

Requires: first shall be swappable with ([swappable.requirements]) p.first and second shall be swappable with p.second.

Effects: Swaps first with p.first and second with p.second.

20.4.3 Specialized algorithms [pairs.spec]

template <class T1, class T2> constexpr bool operator==(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: x.first == y.first && x.second == y.second.

template <class T1, class T2> constexpr bool operator<(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: x.first < y.first || (!(y.first < x.first) && x.second < y.second).

template <class T1, class T2> constexpr bool operator!=(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: !(x == y).

template <class T1, class T2> constexpr bool operator>(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: y < x.

template <class T1, class T2> constexpr bool operator>=(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: !(x < y).

template <class T1, class T2> constexpr bool operator<=(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: !(y < x).

template<class T1, class T2> void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));

Effects: As if by x.swap(y).

Remarks: This function shall not participate in overload resolution unless is_swappable_v<T1> is true and is_swappable_v<T2> is true.

template <class T1, class T2> constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);

Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y)), where V1 and V2 are determined as follows: Let Ui be decay_t<Ti> for each Ti. Then each Vi is X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui.

Example: In place of:

  return pair<int, double>(5, 3.1415926);   // explicit types

a C++ program may contain:

  return make_pair(5, 3.1415926);           // types are deduced

 — end example ]

20.4.4 Tuple-like access to pair [pair.astuple]

template <class T1, class T2> struct tuple_size<pair<T1, T2>> : integral_constant<size_t, 2> { };

tuple_element<0, pair<T1, T2>>::type

Value: the type T1.

tuple_element<1, pair<T1, T2>>::type

Value: the type T2.

template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>& p) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>& p) noexcept; template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&& p) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&& p) noexcept;

Returns: If I == 0 returns a reference to p.first; if I == 1 returns a reference to p.second; otherwise the program is ill-formed.

template <class T, class U> constexpr T& get(pair<T, U>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<T, U>& p) noexcept; template <class T, class U> constexpr T&& get(pair<T, U>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<T, U>&& p) noexcept;

Requires: T and U are distinct types. Otherwise, the program is ill-formed.

Returns: A reference to p.first.

template <class T, class U> constexpr T& get(pair<U, T>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<U, T>& p) noexcept; template <class T, class U> constexpr T&& get(pair<U, T>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<U, T>&& p) noexcept;

Requires: T and U are distinct types. Otherwise, the program is ill-formed.

Returns: A reference to p.second.

20.4.5 Piecewise construction [pair.piecewise]

struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; constexpr piecewise_construct_t piecewise_construct{};

The struct piecewise_construct_t is an empty structure type used as a unique type to disambiguate constructor and function overloading. Specifically, pair has a constructor with piecewise_construct_t as the first argument, immediately followed by two tuple ([tuple]) arguments used for piecewise construction of the elements of the pair object.