std::shift_left, std::shift_right
From cppreference.com
| Defined in header <algorithm>
|
||
template< class ForwardIt >
constexpr ForwardIt shift_left( ForwardIt first, ForwardIt last,
typename std::iterator_traits<ForwardIt>::
difference_type count );
|
(1) | (since C++20) |
template< class ForwardIt >
constexpr ForwardIt shift_right( ForwardIt first, ForwardIt last,
typename std::iterator_traits<ForwardIt>::
difference_type count );
|
(2) | (since C++20) |
template< class ExecutionPolicy, class ForwardIt >
ForwardIt shift_left( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last,
typename std::iterator_traits<ForwardIt>::
difference_type count );
|
(3) | (since C++20) |
template< class ExecutionPolicy, class ForwardIt >
ForwardIt shift_right( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last,
typename std::iterator_traits<ForwardIt>::
difference_type count );
|
(4) | (since C++20) |
Shifts the elements in the target range [first, last) by count positions. If count is not less than std::distance(first, last), does nothing.
1)
shift_left shifts the elements towards the beginning of the target range. For every integer
i starting from 0 to std::distance(first, last) - count - 1, moves the element originally at position std::next(first, count + i) to position std::next(first, i).2)
shift_right shifts the elements towards the end of the target range. For every integer
i starting from std::distance(first, last) - count - 1 to 0, moves the element originally at position std::next(first, i) to position std::next(first, count + i). If
ForwardIt does not meet the requirements of LegacyBidirectionalIterator, the shifting process is performed by swapping elements instead, the swap order is unspecified.3,4) Same as (1,2), but the move order is determined by
policy. These overloads participate in overload resolution only if
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true.If any of the following conditions is satisfied, the behavior is undefined:
count >= 0is nottrue.- The type of
*firstis not MoveAssignable. - For
shift_right,ForwardItis neither LegacyBidirectionalIterator nor ValueSwappable.
Parameters
| first, last | - | the pair of iterators defining the target range |
| count | - | the shift offset |
| policy | - | the execution policy to use |
| Type requirements | ||
-ForwardIt must meet the requirements of LegacyForwardIterator.
| ||
Return value
Let size be the std::distance(first, last):
1,3)
std::next(first, std::max(size - count, 0))2,4)
std::next(first, std::min(size, count))Complexity
Given \(\scriptsize N\)N as std::distance(first, last):
1,3) At most \(\scriptsize \max(N-\mathtt{count},0)\)max(N-
count,0) assignments.2,4) At most \(\scriptsize \max(N-\mathtt{count},0)\)max(N-
count,0) assignment or 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
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_lib_shift |
201806L |
(C++20) | std::shift_left and std::shift_right
|
Example
Run this code
import std;
struct S
{
int value{0};
bool specified_state{true};
S(int v = 0) : value{v} {}
S(const S& rhs) = default;
S(S&& rhs) { *this = std::move(rhs); }
S& operator=(const S& rhs) = default;
S& operator=(S&& rhs)
{
if (this != &rhs)
{
value = rhs.value;
specified_state = rhs.specified_state;
rhs.specified_state = false;
}
return *this;
}
};
template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
for (const auto& s : v)
{
if constexpr (std::is_same_v<T, S>)
s.specified_state ? os << s.value << ' ' : os << ". ";
else if constexpr (std::is_same_v<T, std::string>)
os << (s.empty() ? "." : s) << ' ';
else
os << s << ' ';
}
return os;
}
template <int width = 16>
void println(auto&&... s)
{
std::cout << std::left;
std::stringstream ss;
((ss.str(""), ss << s, std::cout << std::setw(width) << ss.str()), ...);
std::cout << '\n';
}
int main()
{
std::vector<S> a{1, 2, 3, 4, 5, 6, 7};
std::vector<int> b{1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> c{"", "", "", "", "", "", ""};
println("vector<S>", "vector<int>", "vector<string>");
println(a, b, c);
std::shift_left(begin(a), end(a), 3);
std::shift_left(begin(b), end(b), 3);
std::shift_left(begin(c), end(c), 3);
println(a, b, c);
std::shift_right(begin(a), end(a), 2);
std::shift_right(begin(b), end(b), 2);
std::shift_right(begin(c), end(c), 2);
println(a, b, c);
std::shift_left(begin(a), end(a), 8); // has no effect: n >= last - first
std::shift_left(begin(b), end(b), 8); // ditto
std::shift_left(begin(c), end(c), 8); // ditto
println(a, b, c);
// std::shift_left(begin(a), end(a), -3); // UB, e.g. segfault
}
Possible output:
vector<S> vector<int> vector<string>
1 2 3 4 5 6 7 1 2 3 4 5 6 7
4 5 6 7 . . . 4 5 6 7 5 6 7 . . .
. . 4 5 6 7 . 4 5 4 5 6 7 5 . . .
. . 4 5 6 7 . 4 5 4 5 6 7 5 . . .
See also
(C++23)(C++23) |
shifts elements in a range (algorithm function object) |
(C++11) |
moves a range of elements to a new location (function template & algorithm function object) |
(C++20) |
|
(C++11) |
moves a range of elements to a new location in backwards order (function template & algorithm function object) |
(C++20) |
|
| rotates the order of elements in a range (function template & algorithm function object) | |
(C++20) |