迭代器和范围的概念

383 阅读4分钟

迭代器和范围的概念

本文列出迭代器和范围的所有基本概念,在算法和类似函数中使用它们很有用。

注意,范围的概念在命名空间std::ranges中,而不是std中。

范围和视图的概念

定义了几个概念,要求参数为(特定的)范围。它们与迭代器的概念相对应。

std::ranges::range<Rg>

  • 保证Rg是一个有效范围

  • 这意味着Rg类型的对象支持使用std::ranges::begin()和std::begin::end()来遍历元素。

    如果range是一个数组,或者提供begin()和end()成员,或者可以与独立的begin()和end()函数一起使用,就会出现这种情况。

    此外,对于std::ranges::begin()和std::ranges::end(),应用以下约束:

    • 它们必须在(平摊)常数时间内操作。

    • 他们不会修改射程。

    • begin()在多次调用时产生相同的位置(除非range至少没有提供前向迭代器)。

    这意味着我们可以以良好的性能遍历所有元素(甚至多次,除非我们有纯输入迭代器)。

  • 对于rg类型的对象,支持std::ranges::begin(rg)和std::ranges::end(rg)


std::ranges::output_range<Rg, T>

  • 保证Rg是一个范围,它至少提供了接受T类型值的输出迭代器(你可以用来写迭代器)。

  • std::range满足

  • std::output iterator满足迭代器类型和T


std::ranges::input_range<Rg>

  • 保证Rg是一个至少提供输入迭代器(你可以用来读取的迭代器)的范围。、

  • std::range 足

  • std::input iterator满足迭代器类型


std: :ranges: : forward_range<Rg>

  • 保证Rg是一个至少提供前向迭代器的范围(迭代器可以用于读写和多次迭代)。

  • std::input range满足

  • std::forward iterator满足迭代器类型


std: :ranges: :bidirectional_range<Rg>

  • 保证Rg是一个至少提供双向迭代器的范围(迭代器可以用于读写,也可以用于反向迭代器)。

  • std::forward range满足

  • std::bidirectional iterator满足迭代器类型


std::ranges: :random_access_range<Rg>

  • 保证Rg是一个提供随机访问迭代器的范围(迭代器可以用于读写、来回跳转和计算距离)。

  • std:: bidirectional range满足

  • std::random access iterator满足iteratortype


std::ranges::contiguous_range<Rg>

  • 保证Rg是一个范围,它提供随机访问迭代器,并附加了元素存储在连续内存中的约束。

  • std::随机访问范围满足

  • std::连续迭代器满足迭代器类型-调用std::ranges::data()产生一个指向第一个元素的原始指针


std::ranges::sized_range<Rg>

  • 保证Rg是一个范围,其中元素的数量可以计算为它在常数时间内开始和结束的差值。

  • 也就是说,std::ranges::size()是为Rg类型的对象定义的。

  • 要表明一个类型不满足这个概念,尽管它提供了size(),你可以定义std::disable size range产生true。

  • std::range是满足的-支持调用std::ranges::size()

  • std::ranges:: disable size range没有定义为true


std::ranges::common_range<Rg>

  • 保证Rg是一个范围,其中开始迭代器和哨兵(结束迭代器)具有相同的类型。

  • 保证总是由:-所有标准容器(向量,列表等)

  • 空视图-单一视图-通用视图。

  • 保证不是由- take视图- const drop视图- iota视图,没有结束值或不同类型的结束值。对于其他视图,它取决于底层范围的类型。

  • std::range满足std::ranges::iterator t和std::ranges::sentinel t类型相同。


std::ranges::borrowed_range<Rg>

  • 迭代器不受范围生命周期的限制。这意味着迭代器使用起来更安全,因为当创建迭代器的范围被破坏时,迭代器不会摇摆不定。但是,如果范围的迭代器指向一个基础范围,而基础范围已经不存在,那么它们仍然可以悬浮。

    如果Rg是一个Ivalue(例如一个有名称的对象),或者如果变量模板std::ranges::enable borrow range为真,则给出保证,对于以下视图是这样的情况:subrange,ref view,string view, span,io


std::ranges::view<Rg>

  • 保证 Rg 是一个视图(一个复制、分配和销毁成本较低的范围)。

一种观点有以下要求:

  • 它必须是一个范围(支持在元素上迭代)。

  • 它必须是可移动的。

  • 移动构造函数/赋值、复制建构子/赋值(如果可用)和析构函数必须具有恒定的复杂度(它们所花费的时间并不取决于元素的数量)。

除了最后一个需求外,所有需求都由相应的概念检查。最后一个需求必须由类型的实现者来保证,方法是从 std: : range: : view _ interface 或 std: : range: : view _ base 公开派生,或者专门化 std: : range: : allow _ view < Rg > 以产生 true。

  • std::range is satisfied—std::movableis satisfied

  • 变量模板std::enable view为true


std::ranges: :viewable_range<Rg>

  • 确保Rg是一个可以使用std::views::al1()适配器安全地转换为视图的范围。

  • 如果Rg已经是一个视图或一个范围的i值,则满足这个概念。

  • std::range<Rg>满足- std:: borrow range<Rg>std::view<std::remove cvref t<Rg>


开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情