std::ranges::iter_swap
std::ranges::iter_move
template <class I>
void SwapIters(I lhs, I rhs)
{
using std::swap;
swap(*lhs, *rhs);
}
Proxy reference type could be pair<T&,T&>
, so this just swapped two rvalues.
- Improvement upon
std::iter_swap
from C++98.
- Intentionally designed customization point for proxy iterators.
- Used by all
std::ranges
algorithms that swap stuff.
template <class I>
std::iter_value_t<I> Extract(I iter)
{
return std::move(*iter);
}
Proxy reference type could be pair<T&,T&>
, so this moved an rvalue.
- Didn’t exist before, even after
std::move
came along.
- Another customization point for proxy iterators.
- Used by all
std::ranges
algorithms that move values.
Another benefit of sentinels:
Won't work with the old algorithms.*
But how does one "customize" std::ranges::iter_move
?
Obtains an rvalue reference or a prvalue temporary from a given iterator.
A call to ranges::iter_move
is expression-equivalent to:
iter_move(std::forward<T>(t))
, ifstd::remove_cvref_t<T>
is a class or enumeration type and the expression is well-formed in unevaluated context, where the overload resolution is performed with the following candidates:void iter_move();
- any declarations of
iter_move
found by argument-dependent lookup.
- otherwise,
std::move(*std::forward<T>(t))
if*std::forward<T>(t)
is well-formed and is an lvalue, - otherwise,
*std::forward<T>(t)
if*std::forward<T>(t)
is well-formed and is an rvalue.
In all other cases, a call to ranges::iter_move
is ill-formed, which can result in substitution failure when ranges::iter_move(e)
appears in the immediate context of a template instantiation.
If ranges::iter_move(e)
is not equal to *e
, the program is ill-formed, no diagnostic required.
class inner_iterator
{
private:
using base_value_type = std::ranges::range_value_t<TBase>;
using base_reference = std::ranges::range_reference_t<TBase>;
public:
using value_type = std::pair<base_value_type, base_value_type>;
using reference = std::pair<base_reference, base_reference>;
friend constexpr auto iter_move(inner_iterator i)
{
using base_rref = std::ranges::range_rvalue_reference_t<TBase>;
return std::pair<base_rref, base_rref> {
std::ranges::iter_move(i._current_outer),
std::ranges::iter_move(i._current_inner)
};
}
};
class inner_iterator
{
private:
using base_value_type = std::ranges::range_value_t<TBase>;
using base_reference = std::ranges::range_reference_t<TBase>;
public:
using value_type = std::pair<base_value_type, base_value_type>;
using reference = std::pair<base_reference, base_reference>;
friend constexpr auto iter_move(inner_iterator i)
{
return std::pair {
std::ranges::iter_move(i._current_outer),
std::ranges::iter_move(i._current_inner)
};
}
};
Views that expose elements multiple times can't use iter_move
.