Namespaces
Variants

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

From cppreference.com
 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Non-modifying sequence operations    
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17)(C++11)
(C++20)(C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
(C++11)    

Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations


 
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Fold operations (Helper templates)
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
       
       
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
       
       
Permutation operations
Specialized <memory> algorithms
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 ranges::swap_ranges_result<ranges::borrowed_iterator_t<R1>,
                                     ranges::borrowed_iterator_t<R2>>
    swap_ranges( R1&& r1, R2&& r2 );
(2) (since C++20)
template< /*execution-policy*/ Ep,
          std::random_access_iterator I1, std::sized_sentinel_for<I1> S1,
          std::random_access_iterator I2, std::sized_sentinel_for<I2> S2 >
    requires std::indirectly_swappable<I1, I2>
ranges::swap_ranges_result<I1, I2>
    swap_ranges( Ep&& policy, I1 first1, S1 last1, I2 first2, S2 last2 );
(3) (since C++26)
template< /*execution-policy*/ Ep,
          /*sized-random-access-range*/ R1, /*sized-random-access-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>>
    swap_ranges( Ep&& policy, R1&& r1, R2&& r2 );
(4) (since C++26)
Helper types
template< class I1, class I2 >
using swap_ranges_result = ranges::in_in_result<I1, I2>;
(5) (since C++20)

For the definition of /*execution-policy*/, see this page; for the definition of /*sized-random-access-range*/, see this page.

Exchanges elements between two ranges.

1) The two ranges are [first1last1) and [first2last2).
2) The two ranges are r1 and r2.
3,4) Same as (1,2), but executed according to policy.

If the two ranges overlap, the behavior is undefined.

The function-like entities described on this page are algorithm function objects (informally known as niebloids), that is:

Parameters

first1, last1 - the iterator-sentinel pair defining the first range
r1 - the first range
first2, last2 - the iterator-sentinel pair defining the second range
r2 - the second range

Return value

A ranges::swap_ranges_result object where:

  • The data member in1 holds the an iterator past the last swapped element in the first range, or an iterator to the beginning of the first range if no element is swapped.
  • The data member in2 holds the an iterator past the last swapped element in the second range, or an iterator to the beginning of the second range if no element is swapped.

Complexity

Given

  • N1 as ranges::distance(first1, last1) or ranges::distance(r1), and
  • N2 as ranges::distance(first2, last2) or ranges::distance(r2):
1-4) Exactly min(N1,N2) swaps.

Exceptions

3,4) During the execution process:
  • If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
  • If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).

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 R>
    constexpr auto get_end(R&& r)
    {
        return ranges::end(r);
    }
    
    template<ranges::forward_range R>
    constexpr auto get_end(R&& r)
    {
        return ranges::next(ranges::begin(r), ranges::end(r));
    }
    
    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), get_end(r1),
                       ranges::begin(r2), get_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, const auto& 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

swaps two ranges of elements
(function template) [edit]
swaps the elements pointed to by two iterators
(function template) [edit]
swaps the values of two objects
(function template) [edit]
swaps the values referenced by two dereferenceable objects
(customization point object)[edit]
swaps the values of two objects
(customization point object)[edit]