8 General utilities library [utilities]

8.2 Utility components [utility]

This subclause contains some basic function and class templates that are used throughout the rest of the library.

Header <experimental/ranges/utility> synopsis

The header <experimental/ranges/utility> defines several types, function templates, and concepts that are described in this Clause. It also defines the templates tagged and tagged_pair and various function templates that operate on tagged_pair objects.

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  // [utility.swap], swap:
  namespace {
    constexpr unspecified swap = unspecified;
  }

  // [utility.exchange], exchange:
  template <MoveConstructible T, class U=T>
    requires Assignable<T&, U>
  constexpr T exchange(T& obj, U&& new_val) noexcept(see below);

  // [taggedtup.tagged], struct with named accessors
  template <class T>
  concept bool TagSpecifier = see below;

  template <class F>
  concept bool TaggedType = see below;

  template <class Base, TagSpecifier... Tags>
    requires sizeof...(Tags) <= tuple_size<Base>::value
  struct tagged;

  // [tagged.pairs], tagged pairs
  template <TaggedType T1, TaggedType T2> using tagged_pair = see below;

  template <TagSpecifier Tag1, TagSpecifier Tag2, class T1, class T2>
  constexpr see below make_tagged_pair(T1&& x, T2&& y);
}}}}

namespace std {
  // [tagged.astuple], tuple-like access to tagged
  template <class Base, class... Tags>
  struct tuple_size<experimental::ranges::tagged<Base, Tags...>>;

  template <size_t N, class Base, class... Tags>
  struct tuple_element<N, experimental::ranges::tagged<Base, Tags...>>;
}

8.2.1 swap [utility.swap]

The name swap denotes a customization point object ([customization.point.object]). The effect of the expression ranges::swap(E1, E2) for some expressions E1 and E2 is equivalent to:

  • (void)swap(E1, E2), if that expression is valid, with overload resolution performed in a context that includes the declarations

      template <class T>
      void swap(T&, T&) = delete;
      template <class T, size_t N>
      void swap(T(&)[N], T(&)[N]) = delete;
    

    and does not include a declaration of ranges::swap. If the function selected by overload resolution does not exchange the values referenced by E1 and E2, the program is ill-formed with no diagnostic required.

  • Otherwise, (void)swap_ranges(E1, E2) if E1 and E2 are lvalues of array types ( ISO/IEC 14882:2014 §[basic.compound]) of equal extent and ranges::swap(*(E1), *(E2)) is a valid expression, except that noexcept(ranges::swap(E1, E2)) is equal to noexcept(ranges::swap(*(E1), *(E2))).

  • Otherwise, if E1 and E2 are lvalues of the same type T which meets the syntactic requirements of MoveConstructible<T> and Assignable<T&, T>, exchanges the referenced values. ranges::swap(E1, E2) is a constant expression if the constructor selected by overload resolution for T{std::move(E1)} is a constexpr constructor and the expression E1 = std::move(E2) can appear in a constexpr function. noexcept(ranges::swap(E1, E2)) is equal to is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value. If either MoveConstructible or Assignable is not satisfied, the program is ill-formed with no diagnostic required.

  • Otherwise, ranges::swap(E1, E2) is ill-formed.

Remark: Whenever ranges::swap(E1, E2) is a valid expression, it exchanges the values referenced by E1 and E2 and has type void.

8.2.2 exchange [utility.exchange]

template <MoveConstructible T, class U=T> requires Assignable<T&, U> constexpr T exchange(T& obj, U&& new_val) noexcept(see below);

Effects: Equivalent to:

T old_val = std::move(obj);
obj = std::forward<U>(new_val);
return old_val;

Remarks: The expression in noexcept is equivalent to:

is_nothrow_move_constructible<T>::value &&
is_nothrow_assignable<T&, U>::value