This subclause contains some basic function and class templates that are used throughout the rest of the library.
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...>>; }
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.
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