В C ++ 20 <algorithm>
заголовок получает два новых алгоритма: shift_left()
иshift_right()
. Оба они принимают любой LegacyForwardIterator. Ведь shift_left()
указано, что «шаги выполняются в порядке возрастания, i
начиная с 0
»; для shift_right()
, указано, что «если ForwardIt
соответствует требованиям LegacyBidirectionalIterator, то перемещения выполняются в порядке убывания, i
начиная с last - first - n - 1
».
Я могу придумать достаточно простой способ реализации shift_left()
:
template <typename ForwardIt>
constexpr inline ForwardIt shift_left(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
if (n <= 0) return last;
ForwardIt it = first;
for (; n > 0; --n, ++it) {
if (it == last) return first;
}
return std::move(it, last, first);
}
Если ForwardIt
отвечает требованиям LegacyBidirectionalIterator, я вижу, что это shift_right()
может быть реализовано так же, как и shift_left()
. Тем не менее, совершенно не ясно, как можно реализовать shift_right()
недионаправленные прямые итераторы.
Я разобрался с алгоритмом, который использует пространство [first, first+n)
как пустое место для замены элементов, но он кажется немного более расточительным, чем алгоритм shift_left()
выше:
template <typename ForwardIt>
constexpr inline ForwardIt shift_right(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
if (n <= 0) return first;
ForwardIt it = first;
for (; n > 0; --n, ++it) {
if (it == last) return last;
}
ForwardIt ret = it;
ForwardIt ret_it = first;
for (; it != last; ++it) {
std::iter_swap(ret_it, it);
ret_it++;
if (ret_it == ret) ret_it = first;
}
return ret;
}
Будет ли лучший или "предполагаемый" способ реализации shift_right()
?
std::move
вместоstd::copy
...