std::ranges::move() algorithm
- od C++20
- Simplified
- Detailed
// (1)
constexpr move_result<I, O>
move( I first, S last, O result );
// (2)
constexpr move_result<ranges::borrowed_iterator_t<R>, O>
move( R&& r, O result );
The type of arguments are generic and have following constraints:
I
-std::input_iterator
S
-std::sentinel_for<I>
O
-std::weakly_incrementable
- (2) -
R
-std::ranges::input_range
Additionally, each overload has the following contraints:
- (1) -
std::indirectly_movable<I, O>
- (2) -
std::indirectly_movable<ranges::iterator_t<R>, O>
// (1)
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::weakly_incrementable O
>
requires std::indirectly_movable<I, O>
constexpr move_result<I, O>
move( I first, S last, O result );
// (2)
template<
ranges::input_range R,
std::weakly_incrementable O
>
requires std::indirectly_movable<ranges::iterator_t<R>, O>
constexpr move_result<ranges::borrowed_iterator_t<R>, O>
move( R&& r, O result );
With the helper types defined as follows:
template< class I, class O >
using move_result = ranges::in_out_result<I, O>;
-
(1) Moves the elements in the range, defined by [
first
;last
), to another range beginning atresult
.The elements in the moved-from range will still contain valid values of the appropriate type, but not necessarily the same values as before the move.
Undefined BehaviourThe behavior is undefined if
result
is within the range [first
;last
). In this case,ranges::move_backward
may be used instead. -
(2) Same as (1), but uses
r
as the source range, as if usingranges::begin(r)
asfirst
andranges::end(r)
aslast
.
The function-like entities described on this page are niebloids.
Parameters
first last | The range of elements to move. |
r | The range of elements to move. |
result | The beginning of the destination range. |
Return value
A value of type ranges::move_result
initialized as follows:
{
last,
result + N
}
Where N
is the size of the range to move elements from.
Complexity
Exactly N
move assignments.
Exceptions
(none)
Possible implementation
move(1) and move(2)
struct move_fn
{
template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
requires std::indirectly_movable<I, O>
constexpr ranges::move_result<I, O>
operator()(I first, S last, O result) const
{
for (; first != last; ++first, ++result)
*result = ranges::iter_move(first);
return {std::move(first), std::move(result)};
}
template<ranges::input_range R, std::weakly_incrementable O>
requires std::indirectly_movable<ranges::iterator_t<R>, O>
constexpr ranges::move_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r, O result) const
{
return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
}
};
inline constexpr move_fn move {};
Notes
When moving overlapping ranges, ranges::move
is appropriate when moving to the left (beginning of the destination range is outside the source range),
while ranges::move_backward
is appropriate when moving to the right (end of the destination range is outside the source range).
Examples
The following code moves thread objects (which themselves are non copyable) from one container to another.
#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <list>
#include <thread>
#include <vector>
using namespace std::literals::chrono_literals;
void f(std::chrono::milliseconds n)
{
std::this_thread::sleep_for(n);
std::cout << "thread with n=" << n.count() << "ms ended" << std::endl;
}
int main()
{
std::vector<std::jthread> v;
v.emplace_back(f, 400ms);
v.emplace_back(f, 600ms);
v.emplace_back(f, 800ms);
std::list<std::jthread> l;
// std::ranges::copy() would not compile, because std::jthread is non-copyable
std::ranges::move(v, std::back_inserter(l));
}
thread with n=400ms ended
thread with n=600ms ended
thread with n=800ms ended
Hover to see the original license.