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)或通过接受 iteratorsentinelsize 的构造函数(因此需要在此处指定 sized_sentinel_for<S, I>)来构造子范围。

S
末尾迭代器类型。 sized_sentinel_for 概念可确保 S 可用作 I 的 sentinel,并且可以在常数时间内计算 sentinel 与 I 中当前迭代器位置之间的距离。

视图特征

有关下列条目的说明,请参阅视图类特征

特征 说明
范围适配器 views::counted
基础范围 任何范围
元素类型 iter_reference_t<I>
视图迭代器类别 Is 类别相同
已设置大小 如果 Ksubrange::sized
const 可迭代 如果 I 可复制
常见范围 如果 IS 属于同一类型。
借入范围

成员

成员函数 描述
构造函数C++20 构造 subrange
operator PairLikeC++20 subrange 转换为类似对的类型。
advanceC++20 将迭代器移动到指定的距离。
begin 获取指向第一个元素的迭代器。
emptyC++20 测试 subrange 是否为空。
endC++20 获取 subrange 末尾的 sentinel。
nextC++20 创建此 subrange 的副本,但使存储的迭代器向前移动指定距离。
prevC++20 创建此 subrange 的副本,但使存储的迭代器向后移动指定距离。
sizeC++20 获取元素数。
view_interface 继承 描述
backC++20 获取最后一个元素。
dataC++20 获取指向第一个元素的指针。
frontC++20 获取第一个元素。
operator[]C++20 获取指定位置的元素。
operator boolC++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 代码较为有用。
此转换对于将子范围转换为 pairtuple 或效仿 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 的移动构造函数的实现。

包含元素 10、20 和 30 的矢量的图片。第一个元素包含 10,被标记为 begin()。最后一个元素包含 30,被标记为“last element”。最后一个元素之后的虚框指示 sentinel,被标记为 end()。

empty

测试 subrange 是否为空。

constexpr bool empty() const;

参数

无。

返回值

如果 subrange 没有元素,则返回 true。 否则返回 false

end

获取 subrange 末尾的 sentinel

[[nodiscard]] constexpr S end() const;

参数

无。

返回值

subrange 中最后一个元素后面的 sentinel:

包含元素 10、20 和 30 的矢量的图片。第一个元素包含 10,被标记为 begin()。最后一个元素包含 30,被标记为“last element”。最后一个元素之后的虚框指示 sentinel,被标记为 end()。

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)后,会更改报告的大小。

另请参阅

<ranges>
counted
视图类