std::ranges::swap_ranges, std::ranges::swap_ranges_result

From cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Execution policies (C++17)
Non-modifying sequence operations
(C++11)(C++11)(C++11)
(C++17)
Modifying sequence operations
Partitioning operations
Sorting operations
(C++11)
Binary search operations
Set operations (on sorted ranges)
Heap operations
(C++11)
Minimum/maximum operations
(C++11)
(C++17)

Permutations
Numeric operations
Operations on uninitialized storage
(C++17)
(C++17)
(C++17)
C library
 
Constrained algorithms
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Permutations
Constrained numeric operations
Fold operations
Operations on uninitialized storage
Return types
 
Defined in header <algorithm>
Call signature
template< std::input_iterator I1, std::sentinel_for<I1> S1,

          std::input_iterator I2, std::sentinel_for<I2> S2 >
requires  std::indirectly_swappable<I1, I2>
constexpr swap_ranges_result<I1, I2>

          swap_ranges( I1 first1, S1 last1, I2 first2, S2 last2 );
(1) (since C++20)
template< ranges::input_range R1, ranges::input_range R2 >

requires  std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>>
constexpr swap_ranges_result<ranges::borrowed_iterator_t<R1>,
                             ranges::borrowed_iterator_t<R2>>

          swap_ranges( R1&& r1, R2&& r2 );
(2) (since C++20)
Helper types
template< class I1, class I2 >
using swap_ranges_result = ranges::in_in_result<I1, I2>;
(3) (since C++20)
1) Exchanges elements between first range [first1, first1 + M) and second range [first2, first2 + M) via ranges::iter_swap(first1 + i, first2 + i), where M = ranges::min(ranges::distance(first1, last1), ranges::distance(first2, last2)).
The ranges [first1, last1) and [first2, last2) must not overlap.
2) Same as (1), but uses r1 as the first range and r2 as the second range, as if using ranges::begin(r1) as first1, ranges::end(r1) as last1, ranges::begin(r2) as first2, and ranges::end(r2) as last2.

The function-like entities described on this page are niebloids, that is:

In practice, they may be implemented as function objects, or with special compiler extensions.

Parameters

first1, last1 - the first range of elements to swap
first2, last2 - the second range of elements to swap
r1 - the first range of elements to swap
r2 - the second range of elements to swap.

Return value

{first1 + M, first2 + M}.

Complexity

Exactly M swaps.

Notes

Implementations (e.g. MSVC STL) may enable vectorization when the iterator type models contiguous_iterator and swapping its value type calls neither non-trivial special member function nor ADL-found swap.

Possible implementation

struct swap_ranges_fn {
 
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2>
    requires std::indirectly_swappable<I1, I2>
      constexpr ranges::swap_ranges_result<I1, I2>
        operator() ( I1 first1, S1 last1, I2 first2, S2 last2 ) const {
            for (; !(first1 == last1 or first2 == last2); ++first1, ++first2)
                ranges::iter_swap(first1, first2);
            return {std::move(first1), std::move(first2)};
        }
 
  template<ranges::input_range R1, ranges::input_range R2>
    requires std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>>
      constexpr ranges::swap_ranges_result<ranges::borrowed_iterator_t<R1>,
                                           ranges::borrowed_iterator_t<R2>>
        operator() ( R1&& r1, R2&& r2 ) const {
            return (*this)(ranges::begin(r1), ranges::end(r1),
                           ranges::begin(r2), ranges::end(r2));
        }
};
 
inline constexpr swap_ranges_fn swap_ranges{};

Example

#include <algorithm>
#include <iostream>
#include <list>
#include <string_view>
#include <vector>
 
auto print(std::string_view name, auto const& seq, std::string_view term = "\n") {
    std::cout << name << " : ";
    for (const auto& elem : seq)
        std::cout << elem << ' ';
    std::cout << term;
}
 
int main()
{
    std::vector<char>  p {'A', 'B', 'C', 'D', 'E'};
    std::list<char>    q {'1', '2', '3', '4', '5', '6'};
 
    print("p", p);
    print("q", q, "\n\n");
 
    // swap p[0, 2) and q[1, 3):
    std::ranges::swap_ranges(p.begin(),
                             p.begin() + 4,
                             std::ranges::next(q.begin(), 1),
                             std::ranges::next(q.begin(), 3));
    print("p", p);
    print("q", q, "\n\n");
 
    // swap p[0, 5) and q[0, 5):
    std::ranges::swap_ranges(p, q);
 
    print("p", p);
    print("q", q);
}

Output:

p : A B C D E
q : 1 2 3 4 5 6
 
p : 2 3 C D E
q : 1 A B 4 5 6
 
p : 1 A B 4 5
q : 2 3 C D E 6

See also

(C++20)
swaps the values referenced by two dereferenceable objects
(customization point object)
swaps the values of two objects
(customization point object)
swaps two ranges of elements
(function template)
swaps the elements pointed to by two iterators
(function template)
swaps the values of two objects
(function template)