std::ranges::swap_ranges, std::ranges::swap_ranges_result
From cppreference.com
| 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
[first1, last1) and [first2, last2).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:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
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
in1holds 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
in2holds 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)orranges::distance(r1), and - N2 as
ranges::distance(first2, last2)orranges::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
Run this code
#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) | |
| swaps the elements pointed to by two iterators (function template) | |
| swaps the values of two objects (function template) | |
(C++20) |
swaps the values referenced by two dereferenceable objects (customization point object) |
(C++20) |
swaps the values of two objects (customization point object) |