subrange
类(C++ 标准库)
提供某个范围的部分元素的视图,由起始迭代器和 sentinel 定义。
语法
template<input_or_output_iterator I, sentinel_for<I> S, subrange_kind K>
requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)
class subrange : public view_interface<subrange<I, S, K>>
模板参数
I
起始迭代器类型。 input_or_output_iterator
概念可确保 I
是可以读取所有元素的迭代器。
K
子范围的类型:使用 subrange_kind::sized
指定一个确定大小的子范围。 如果迭代器和 sentinel 可以相减以生成大小,则使用 sized_sentinel_for<S, I>
。 要求 subrange_kind::sized || !sized_sentinel_for<S, I>
会在子范围对象中本地存储该大小,并要求你使用接受 sized_range
的构造函数(为此你需要在此处指定 subrange_kind::sized
)或通过接受 iterator
、sentinel
、size
的构造函数(因此需要在此处指定 sized_sentinel_for<S, I>
)来构造子范围。
S
末尾迭代器类型。 sized_sentinel_for
概念可确保 S
可用作 I
的 sentinel,并且可以在常数时间内计算 sentinel 与 I
中当前迭代器位置之间的距离。
视图特征
有关下列条目的说明,请参阅视图类特征
特征 | 说明 |
---|---|
范围适配器 | views::counted |
基础范围 | 任何范围 |
元素类型 | iter_reference_t<I> |
视图迭代器类别 | 与 I s 类别相同 |
已设置大小 | 如果 K 为 subrange::sized |
是 const 可迭代 |
如果 I 可复制 |
常见范围 | 如果 I 和 S 属于同一类型。 |
借入范围 | 是 |
成员
成员函数 | 描述 |
---|---|
构造函数C++20 | 构造 subrange 。 |
operator PairLike C++20 |
将 subrange 转换为类似对的类型。 |
advance C++20 |
将迭代器移动到指定的距离。 |
begin |
获取指向第一个元素的迭代器。 |
empty C++20 |
测试 subrange 是否为空。 |
end C++20 |
获取 subrange 末尾的 sentinel。 |
next C++20 |
创建此 subrange 的副本,但使存储的迭代器向前移动指定距离。 |
prev C++20 |
创建此 subrange 的副本,但使存储的迭代器向后移动指定距离。 |
size C++20 |
获取元素数。 |
从 view_interface 继承 |
描述 |
back C++20 |
获取最后一个元素。 |
data C++20 |
获取指向第一个元素的指针。 |
front C++20 |
获取第一个元素。 |
operator[] C++20 |
获取指定位置的元素。 |
operator bool C++20 |
测试 subrange 是否为空。 |
备注
当你有起始和末尾迭代器时,subrange
就很有用,但你需要改为传递单个对象。 例如,如果你想要调用某个范围适配器,但已有起始和末尾迭代器,则可以使用 subrange
来包装它们并将 subrange
传递给范围适配器。
要求
标头: <ranges>
(自C++20以来)
命名空间:std::ranges
编译器选项:/std:c++20
或更高版本是必需的。
构造函数
创建 subrange
。
1) subrange() requires default_initializable<I> = default;
2) template <Convertible_to_non_slicing<I> It>
constexpr subrange(It begin, S end) requires (!Store_size);
3) template <Convertible_to_non_slicing<I> It>
constexpr subrange(It begin, S end, const Size_type size) requires (K == subrange_kind::sized);
4) template <Not_same_as<subrange> rg>
requires borrowed_range<rg>
&& Convertible_to_non_slicing<iterator_t<rg>, I>
&& convertible_to<sentinel_t<rg>, S>
constexpr subrange(rg&& r) requires (!_Store_size || sized_range<rg>);
5) template <borrowed_range rg>
requires Convertible_to_non_slicing<iterator_t<rg>, I> && convertible_to<sentinel_t<rg>, S>
constexpr subrange(rg&& r, const _Size_type sizeHint) requires (K == subrange_kind::sized)
参数
begin
指向子范围中第一个元素的迭代器。
end
指向子范围末尾的 sentinel。 它指向的元素不包含在子范围中。
sizeHint
元素中范围的大小。 这用于优化 size
成员函数,如果你想要从类型不效仿 sized_sentinel_for
的迭代器和 sentinel 设置一个确定大小的 subrange
,则它是必需的。
有关模板参数类型的信息,请参阅模板参数。
返回值
一个 subrange
实例。
注解
1) 默认构造存储的迭代器和 sentinel。 大小提示设置为 0。
2) 使用 std::move()
将 begin
迭代器和 end
sentinel 移动到存储的迭代器和 sentinel。
3) 使用 std::move(begin)
初始化存储的迭代器、使用 std::move(end)
初始化存储的 sentinel,使用 size
初始化存储的大小提示,这应该等于第一个和第二个参数之间的距离。
4) 从一个范围构造一个 subrange
。
5) 如果 szHint != ranges::distance(rg)
,则该行为未定义。
counted
范围适配器可以创建一个 subrange
。 该适配器需要一个起始迭代器和一个计数。
示例: counted
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto pos5 = std::ranges::find(v, 5);
auto countedView = std::views::counted(pos5, 5);
for (auto e : countedView) // outputs 5 6 7 8 9
{
std::cout << e << ' ';
}
std::cout << '\n';
// You can pass the range directly if it supports input_or_output_iterator, in which case, the
// count starts from the first element
const char chars[] = { 'H','i',' ','t','h','e','r','e' };
for (char c : std::views::counted(chars, 2))
{
std::cout << c; // outputs Hi
}
}
5 6 7 8 9
Hi
operator PairLike
将 subrange
转换为效仿 pair-like
的类型。
template<not-same-as<subrange> PairLike>
requires pair-like-convertible-from<PairLike, const I&, const S&>
constexpr operator PairLike() const;
参数
无。
有关模板参数类型的信息,请参阅模板参数。
返回值
使用存储的迭代器和 sentinel 直接初始化的 PairLike
值。
该对中最后一个值将是 sentinel。
请记住,sentinel 超过子范围中的最后一个元素,如以下示例所示。
注解
此转换对于接受(第一个、最后一个)对以表示范围的旧的 Boost::Ranges
代码较为有用。
此转换对于将子范围转换为 pair
或 tuple
或效仿 pair_like
的其他类型很有用。 pair_like
类型的一些例子包括:
std::array<T, 2>
std::pair<T, U>
std::ranges::subrange<I, S, K>
std::tuple<T, U>
示例: operator PairLike()
// requires /std:c++20 or later
#include <iostream>
#include <ranges>
#include <vector>
#include <utility>
int main()
{
constexpr int a[] = {0, 1, 2, 3, 4, 5};
std::ranges::subrange rg(a);
rg.advance(2);
const std::pair<const int*, const int*> p = rg;
for (auto e : rg)
{
std::cout << e << ' ';
}
// because the sentinel points after the last element, subtract one to get the last element
std::cout << '\n' << *p.first << ':' << *(p.second - 1) << '\n'; // outputs 2:5
}
2 3 4 5
2:5
advance
按 n
元素调整此 subrange
的迭代器。
constexpr subrange& advance(const iter_difference_t<I> n);
参数
n
要调整迭代器的元素数。 n
可以是正的(向前移动),或者如果 I
是双向的,则它为负(向后移动)。
备注
此函数修改 subrange
中迭代器的当前状态。
如果你前进到超过 subrange
的末尾,则迭代器将设置为 subrange
末尾的 sentinel。
如果你前进到超过 subrange
的开头(使用负的 n
),且你从中生成 subrange
的范围没有元素,则会收到无效的参数异常。
示例 advance
// requires /std:c++20 or later
#include <iostream>
#include <ranges>
#include <string>
#include <vector>
void print(const std::string &msg, auto &&v)
{
std::cout << msg << '\n';
for (auto& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
print("Original vector: ", v); // outputs 0 1 2 3 4 5 6 7 8 9 10
// create a subrange 3 4 5 6
std::ranges::subrange theSubrange{ std::ranges::find(v,3), std::ranges::find(v, 7) };
print("The subrange: ", theSubrange); // outputs 3 4 5 6
auto sr = theSubrange.advance(2); // get a subrange 2 positions to the right of the current iterator location
print("theSubrange.advance(2): ", sr); // outputs 5 6
print("Note that subrange's iterator moved during advance(): ", sr); // outputs 5 6
sr = theSubrange.advance(-3); // Moving before the subrange, but onto a valid element in the original range
print("theSubrange.advance(-3): ", sr); // outputs 2 3 4 5 6
}
Original vector:
0 1 2 3 4 5 6 7 8 9 10
The subrange:
3 4 5 6
theSubrange.advance(2):
5 6
Note that subrange's iterator moved during advance():
5 6
theSubrange.advance(-3):
2 3 4 5 6
begin
获取指向 subrange
中第一个元素的迭代器。
1) constexpr I begin() const requires copyable<I>;
2) [[nodiscard]] constexpr I begin() requires (!std::copyable<I>);
参数
无。
返回值
指向 subrange
中的第一个元素的迭代器。
如果迭代器不可复制,则它返回时会带有 std::move()
。 如果迭代器已移动,则存储的迭代器的状态取决于 I
的移动构造函数的实现。
empty
测试 subrange
是否为空。
constexpr bool empty() const;
参数
无。
返回值
如果 subrange
没有元素,则返回 true
。 否则返回 false
。
end
获取 subrange
末尾的 sentinel
[[nodiscard]] constexpr S end() const;
参数
无。
返回值
subrange
中最后一个元素后面的 sentinel:
sentinel 是从存储的 sentinel 复制构造的。
next
创建此 subrange
的副本,但使存储的迭代器向前移动指定距离。
1) [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const & requires forward_iterator<I>;
2) [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) &&;
参数
n
要向前移动迭代器的元素数。 默认值为 1。 必须为正。
返回值
返回 subrange
的副本,从第 *n
* 个元素开始。
注解
与 advance()
不同,next()
不会更改存储在原始的 subrange
中的迭代器的位置。
返回的 subrange
具有原始子范围具有的所有元素,但迭代器位于不同的位置。
1) 返回值与以下值相同:
auto tmp = *this;
tmp.advance(n);
return tmp;
2) 返回值与以下值相同:
advance(n);
return std::move(*this);
示例: next
// requires /std:c++20 or later
#include <iostream>
#include <ranges>
#include <string>
#include <vector>
void print(const std::string &msg, auto &&v)
{
std::cout << msg << '\n';
for (auto& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
print("Original vector:", v); // 0 1 2 3 4 5 6 7 8 9 10
// create a subrange from the front of v up to (but not including) the element 7
std::ranges::subrange theSubrange{ std::ranges::find(v,1), std::ranges::find(v, 7) };
print("The subrange:", theSubrange); // 1 2 3 4 5 6
auto forward = theSubrange.advance(3); // get a subrange 3 positions to the right of the current iterator location
print("theSubrange.advance(3):", forward); // 4 5 6
// prev()
auto previous = theSubrange.prev(2); // move back 2
print("theSubrange.prev(2):", previous); // 2 3 4 5 6
print("Note that the subrange's iterator did *not* move during prev():", theSubrange); // 4 5 6
}
Original vector:
0 1 2 3 4 5 6 7 8 9 10
The subrange:
1 2 3 4 5 6
theSubrange.next(3):
4 5 6
Note that the original subrange's iterator did *not* move during next():
1 2 3 4 5 6
prev
创建此 subrange
的副本,但使存储的迭代器向后移动指定距离。
[[nodiscard]] constexpr subrange prev(std::iter_difference_t<I> n = 1 ) const
requires std::bidirectional_iterator<I>;
参数
n
要向后移动迭代器的元素数。 默认值为 1。 必须为正。
返回值
返回 subrange
的副本,但使迭代器向后移动 n
个元素。
备注
与 advance()
不同,prev()
不会更改存储在原始的 subrange
中的迭代器的位置。
返回的 subrange
具有原始子范围具有的所有元素,但只是迭代器位于不同的位置。 你可以将返回值看作:
auto tmp = *this;
tmp.advance(-n);
return tmp;
示例 prev
// requires /std:c++20 or later
#include <iostream>
#include <ranges>
#include <string>
#include <vector>
void print(const std::string &msg, auto &&v)
{
std::cout << msg << '\n';
for (auto& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print("Original vector:", v); // 0 1 2 3 4 5 6 7 8 9 10
// create a subrange from the front of v up to (but not including) the element 7
std::ranges::subrange theSubrange{std::ranges::find(v,1), std::ranges::find(v, 7)};
print("The subrange: ", theSubrange); // 1 2 3 4 5 6
auto forward = theSubrange.advance(3); // get a subrange 3 positions to the right of the current iterator location
print("theSubrange.advance(3):", forward); // 4 5 6
// prev()
auto previous = theSubrange.prev(2); // move back 2
print("theSubrange.prev(2):", previous); // 2 3 4 5 6
print("Note that the subrange's iterator did *not* move during prev():", theSubrange); // 4 5 6
}
Original vector:
0 1 2 3 4 5 6 7 8 9 10
The subrange:
1 2 3 4 5 6
theSubrange.advance(3):
4 5 6
theSubrange.prev(2):
2 3 4 5 6
Note that the subrange's iterator did *not* move during prev():
4 5 6
size
获取 subrange
中的元素数。
constexpr size() const
requires (K == ranges::subrange_kind::sized);
参数
无。
返回值
subrange
中的元素的数量。
如果未存储大小(创建 subrange
时指定了 K == ranges::subrange_kind::sized
但未满足 std::sized_sentinel_for<S, I>
时会发生此情况),则将返回起始和末尾迭代器之间的距离作为大小。
更改 begin
迭代器的位置(例如通过 advance
)后,会更改报告的大小。