std::ranges::shift_left, std::ranges::shift_right
来自cppreference.com
<tbody>
</tbody>
| 在标头 <algorithm> 定义
|
||
| 调用签名 |
||
template< std::permutable I, std::sentinel_for<I> S > constexpr ranges::subrange<I> shift_left( I first, S last, std::iter_difference_t<I> n ); |
(1) | (C++23 起) |
template< ranges::forward_range R > requires std::permutable<ranges::iterator_t<R>> constexpr ranges::borrowed_subrange_t<R> shift_left( R&& r, ranges::range_difference_t<R> n ); |
(2) | (C++23 起) |
template< std::permutable I, std::sentinel_for<I> S > constexpr ranges::subrange<I> shift_right( I first, S last, std::iter_difference_t<I> n ); |
(3) | (C++23 起) |
template< ranges::forward_range R > requires std::permutable<ranges::iterator_t<R>> constexpr ranges::borrowed_subrange_t<R> shift_right( R&& r, ranges::range_difference_t<R> n ); |
(4) | (C++23 起) |
将范围 [first, last) 或 r 中的各元素迁移 n 个位置。若 [first, last) 不是有效范围则其行为未定义。
1) 向范围开端迁移元素:
- 若
n == 0 || n >= last - first则无效果。 - 若
n < 0则行为未定义。 - 否则,对于每个
[0,last - first - n)中的整数i,移动原处于位置first + n + i的元素到位置first + i。以i从0开始递增的顺序进行移动。
3) 向范围结尾迁移元素:
- 若
n == 0 || n >= last - first则无效果。 - 若
n < 0则行为未定义。 - 否则,对于每个
[0,last - first - n)中的整数i,移动原处于位置first + i的元素到位置first + n + i。若I满足bidirectional_iterator,则以i从last - first - n - 1开始递减的顺序进行移动。
2,4) 分别同 (1) 与 (3),但以
r 为范围,如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last。在原范围但不在新范围中的元素被置于合法但未指定的状态。
此页面上描述的函数式实体是算法函数对象(非正式地称为 niebloid),即:
参数
| first, last | - | 要迁移的元素范围的迭代器-哨位对 |
| r | - | 要迁移的元素范围 |
| n | - | 要迁移的位置数 |
返回值
1,2)
{first, /*NEW_LAST*/},其中 NEW_LAST 为结果范围的结尾:
- 若
n小于last - first,则等价于first + (last - first - n); - 否则等价于
first。
3,4)
{/*NEW_FIRST*/, last},其中 NEW_FIRST 为结果范围的开始:
- 若
n小于last - first,则等价于first + n; - 否则等价于
last。
复杂度
1,2) 最多赋值
ranges::distance(first, last) - n 次。3,4) 最多赋值或交换
ranges::distance(first, last) - n 次。注解
常见实现上,若 I 满足 bidirectional_iterator 或(更好地)random_access_iterator,则 ranges::shift_left / ranges::shift_right 会有更好的性能。
实现(例如 MSVC STL )可能在迭代器类型实现 contiguous_iterator ,并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。
| 功能特性测试宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_shift |
202202L |
(C++23) | std::ranges::shift_left 和std::ranges::shift_right
|
示例
运行此代码
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
struct S
{
int value{0};
bool specified_state{true};
S(int v = 0) : value{v} {}
S(S const& rhs) = default;
S(S&& rhs) { *this = std::move(rhs); }
S& operator=(S const& 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, std::vector<T> const& 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;
}
int main()
{
std::cout << std::left;
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{"α", "β", "γ", "δ", "ε", "ζ", "η"};
std::cout << "vector<S> \tvector<int> \tvector<string>\n";
std::cout << a << " " << b << " " << c << '\n';
std::ranges::shift_left(a, 3);
std::ranges::shift_left(b, 3);
std::ranges::shift_left(c, 3);
std::cout << a << " " << b << " " << c << '\n';
std::ranges::shift_right(a, 2);
std::ranges::shift_right(b, 2);
std::ranges::shift_right(c, 2);
std::cout << a << " " << b << " " << c << '\n';
std::ranges::shift_left(a, 8); // 无效果: n >= last - first
std::ranges::shift_left(b, 8); // 同上
std::ranges::shift_left(c, 8); // 同上
std::cout << a << " " << b << " " << c << '\n';
// std::ranges::shift_left(a, -3); // UB
}
可能的输出:
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 . . δ ε ζ η .
参阅
(C++20) |
将范围中元素移到新位置 (算法函数对象) |
(C++20) |
从后往前将范围中元素移到新位置 (算法函数对象) |
(C++20) |
旋转范围中的元素顺序 (算法函数对象) |
(C++20) |
迁移范围中元素 (函数模板) |