C++20新特性—range(一)

2023-05-16

1.range的概念

“Ranges”实际上可理解为一个接口规范(C++20中的concept),它针对集合,提供begin()和end()两个方法,返回一个指示类(iterator),然后就可以枚举集合中的所有元素。由此,以前标准库中所有的容器类都满足range定义。

(注:集合应包括数组、链表等“一维”结构类型,也应该包括矩阵、树等“二维”结构类型,现在的range因有先后顺序的概念,因而在逻辑上是线性结构)。

按照一个集合可以进行如何枚举,有下面的特征:

将以前的容器类按照上面的标准进行分类如下:

另外,如果按读与写进行分类,可有input_range和output_range。集合不同,与之相关的iterator也不同(见下面描述)。

2.iterator category

iterator是集合访问的“指示器”,正是通过它才能访问某个特定元素和如何访问集合元素。根据集合的不同,iterator也不同,目前有6种iterator类型。

  • input iterator:只能向前移动,每次只能移动一步,只读且只能读一次它指向的东西。它以一个输入文件中的 read pointer为原型, istream_iterator 就是这一种类的典型代表。
  • output iterator:只能向前移动,每次只能移动一步,只写且只能写一次它指向的东西。它以一个输出文件中的 write pointer为原型,ostream_iterator是这一种类的典型代表。
  • forward iterator:在 input和 output iterator基础上,加上可以多次读写它指向的东西,即可用于 multi-pass 运算。单向访问数据结构的iterator都可属于此类。
  • bidirectional iterator:在 forward iterator基础上,加上和向前一样的向后移动的能力。双向链表以及可以双向访问的set,map等的iterator都属于此类。
  • random access iterator:在bidirectional iterator基础上,加上了 "iterator arithmetic"(“迭代器运算”)的能力,即在常量时间里向前或者向后跳转一个任意的距离,有点类似于指针运算。random access iterator是以pointer(指针)为原型的,vector,deque 和 string 的 iterator属于此类。
  • contiguous iterator:在random access iterator基础上,要求元素的存储区域是连续的,即要求std::pointer_from(i) == std::addressof(*i)及std::pointer_from(i + n) == std::pointer_from(i) + n。contiguous iterator是以数组为原型的,vector, string的 iterator属于此类,但deque的iterator通常不是。

下图是关于几类iterator的描述(来自于网络)。

 

3.range的意义

Range概念的出现,感觉上把集合类(容器类)的概念更抽象化(学术化)了,ranges库中有许多concept,从外部access的角度,对以前的各种容器类/枚举类进行了划分,概念化后,对容器类的扩展和自定义都有帮助。

另外,STL在使用上,大致有两个不方便,一是大量应用iterator,二是集合操作写法不直观(简洁)。

Iterator主要有两个作用:用于移动元素的指示位置(操作符:+,-,++,--)和得到元素内容(操作符:->,*),如果不是适用于集合整体,必须用iterator指明范围,因此集合操作中存在大量iterator,当然,还有一种办法是构造一个子集,然后将操作施加于子集。

有了各种range::view的操作后,就不需iterator了,从这个意义上讲,range的一个作用可以隐藏iterator。

4. ADL(Argument-dependent lookup)

ADL(Argument-dependent lookup)的意思是当编译器对无限定域的函数调用进行名字查找时,除了当前名字空间域以外,也会把函数参数类型所处的名字空间加入查找的范围,最明显的例子如在一个命名空间中,重载了符号+,我们在使用这个+重载函数时,可以不指定其所在的命名空间,编译器会自动给我们加上:using XXX。

namespace NA
{
   class number
  {
    public:
        number()  {};
  };
  
  void doit(number& one)
  {
      std::cout<<"NA doit "<<std::endl;
  }
}
namespace NB
{
  class number
  {
    public:
        number()  {};
  };
  void doit(number& one)
  {
      std::cout<<"NB doit "<<std::endl;
  }
}
int main() 
{
  NA::number aa;
  doit(aa);    // invoke NA::doit()
  NB::number bb;
  doit(bb);    // invoke NN::doit()
}

上面例子中的number类和doit函数完全相同,main中调用doit时并没有指定namespace,而靠的是其参数的namespace找到NA或NB。

5.定制点对象Customization point object(CPO

ranges库中有许多被称为“定制点对象Customization point object)”的类(函数),如range:begin等。所谓Customization point object,顾名思义,是库的编写者为扩展库的适用范围,将某个接口开放出来,使用者可以按规则进行自定义,即“框架”由库提供,“实现”由使用者提供,最终的代码中库通过Customization point来调用使用者的代码,二者完美结合。例如类中虚函数其实就可以看作是一种Customization point。将std::range:begin等写成定制点对象方式,无非想让其更加generic。

函数的转发调用,也是一种实现CP的方法,例如上面的begin,最简单的实现示意如下:

auto range::begin(T a, Args…)
{
    return a.begin(Args…)
}

但是作为库的话,就不能如上面那么简单了。下面这个例子是2014年Eric Niebler博文(https://ericniebler.com/2014/10/21/customization-point-design-in-c11-and-beyond/)中提供的一个CPO的例子,大概是现在range::begin的一个简化示意,稍有改动。

namespace mystd
{
  namespace __detail
  {
    // define begin for arrays
    template<class T, size_t N>
    constexpr T* begin(T (&a)[N]) noexcept
    {
      return a;
    }
 
    // Define begin for containers  (trailing return type needed for SFINAE)
    template<class _RangeLike>
    constexpr auto begin(_RangeLike && rng)   //->decltype(std::forward<_RangeLike>(rng).begin())
    {
      return std::forward<_RangeLike>(rng).begin();
    }
 
    struct __begin_fn
    {
      template<class R>
      constexpr auto operator()(R && rng) const //-> decltype(begin(std::forward<R>(rng)))
      {
        return begin(std::forward<R>(rng));
      }
    };
  }
  // To avoid ODR violations:
  template<class T>
  struct __static_const
  {
    static constexpr T value{};
  };
 
  template<class T>
  constexpr T __static_const<T>::value;
 
  // std::begin is a global function object!
  namespace
  {
    constexpr auto const & begin =
        __static_const<__detail::__begin_fn>::value;
  }
}
namespace NS {
  struct S {};
  void * begin( S & s )  {std::cout<<"here"; return nullptr;}
}

int main() 
{
 NS::S s;
  void*p = mystd::begin(s); // calls NS::begin(s)
}

这个例子有点晦涩,可作为参考,结果是,虽然看起来调用的是mystd空间中的begin,其实是调用NS中的begin。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++20新特性—range(一) 的相关文章

  • 给定 2 个整数列表,如何找到不重叠的范围?

    Given x 5 30 58 72 y 8 35 53 60 66 67 68 73 目标是迭代x i并找到值y那大于x i但不大于x i 1 假设两个列表都已排序并且所有项目都是唯一的 给定所需的输出x and y is 5 8 30
  • 生成一个范围内的随机偶数?

    这是我遵循的格式 int randomNum rand nextInt max min 1 min 这是我的代码 我正在尝试获取 1 到 100 之间的随机偶数 Random rand new Random int randomNum ra
  • Python argparse 值范围帮助消息外观

    我有一个程序的参数 它是 1 100 之间的整数 我只是不喜欢它在使用 argparse 时在 h 帮助消息中显示的方式 它实际上列出了 0 1 2 3 4 5 等 有什么方法可以改变这一点或以其他方式表示它吗 Thanks EDIT 对于
  • Python range() 上的“in”运算符时间复杂度

    我有以下功能 def foo length num return num in range length 这个函数的时间复杂度是多少 注意到range 在Python 3上创建一个Range对象 这个函数的时间复杂度是O 1 还是O N 我
  • 如何使用 RefersToRange?

    谁能告诉我如何在vba中使用RefersToRange 以及什么时候需要它 请先提供简单的例子 提前致谢 在Excel中 有一个概念 命名范围 这是一个带有名称的单元格范围 这由Name https msdn microsoft com e
  • 如何从范围内仅复制Excel VBA中的值? [复制]

    这个问题在这里已经有答案了 我正在尝试使用 vba 宏在 Excel 中将值从表复制到范围 但我不需要表格式 只需要它的值 我怎样才能实现这个目标 这是代码的一部分 Source range Set r Sheets Sheet1 Rang
  • 将整个范围转换为大写而不循环遍历所有单元格

    现在我正在使用以下代码将股票代码列表从小写字母转换为大写字母 Dim Tickers As String Dim n As Integer For n 2 To Last Tickers UCase W Cells n 1 Value W
  • numpy `arange` 超过最终值

    我原以为 numpy 的arange start end 生成 start end 范围内的值 下面的示例表明这并不总是正确的 最终值大于end import numpy as np start 2e9 end start 321 step
  • 用于在不同工作簿中选择范围的 VBA 对话框

    我想允许用户选择可能位于不同工作簿中的范围 我尝试使用 inputbox type 8 来执行此操作 它可以选择工作簿中的数据 但不允许我在不同的工作簿中选择范围 因此我想要一个允许我执行此任务的对话框 由于我有空 我为您创建了一个示例 创
  • 在python中生成任意长度的数字升序列表

    我可以调用一个返回升序数字列表的函数吗 IE function 10 会回来 0 1 2 3 4 5 6 7 8 9 你要range https docs python org 3 library functions html func r
  • 生成 -x 和 x 之间的随机 Double [重复]

    这个问题在这里已经有答案了 可能的重复 用Java生成一定范围内的随机数 https stackoverflow com questions 363681 generating random number in a range with j
  • 多个 jQuery-UI 滑块的合计

    我正在尝试实现一个有 4 个 jQuery UI 滑块的页面 并且我想让所有 4 个滑块的总数永远不会超过 400 我不介意以哪种方式实现这一点 它可以从 0 开始 一旦您更改 1 个滑块 剩余的可用总数就会减少 或者将滑块设置为超过最大值
  • postgres 中的 @> 运算符有什么作用?

    我在 postgres 中遇到了一个查询here http johanndutoit net searching in a radius using postgres 它使用 gt 地球物体上的操作员 我到处搜索过 但对这个运算符的含义一无
  • 如何使用IPAddress和IPv4Mask获取IP地址范围?

    我试图在 C NET 2 0 中完成以下任务 给定一个 IPAddress 对象 例如 192 168 127 100 和另一个包含 IPv4Mask 子网掩码的 IPAddress 对象 例如 255 255 248 0 我应该能够计算
  • golang 范围内的指针不起作用

    为什么结果是A 1 A 2 A 2 not A 1 A 2 A 3 我们不能在范围内使用指针吗 这是代码 我设置了一个指针 指向范围循环 但它失败了 package main import fmt type A struct Barry B
  • Python:从区间到值的映射

    我正在重构一个函数 给定一系列隐式定义间隔的端点 检查间隔中是否包含数字 然后返回相应的值 不以任何可计算的方式相关 现在处理这项工作的代码是 if p lt 100 return 0 elif p gt 100 and p lt 300
  • SQL 数据范围最小值最大值类别

    我想确定 2 个类别的范围 A 类和 B 类 A 从 1 到 15 开始 B 从 16 到 31 开始 然后 A 再次从 32 到 40 开始 现在如果运行此查询 select min range max range from table
  • 如何将一组重叠范围划分为不重叠范围?

    假设您有一组范围 0 100 一 0 75 b 95 150 c 120 130 d 显然 这些范围在某些点上重叠 您将如何剖析这些范围以生成不重叠范围的列表 同时保留与其原始范围相关的信息 在本例中为范围后面的字母 例如 运行算法后的上述
  • 如何将工作表和范围作为变量传递?

    我想在子例程之间传递工作表的名称和范围 以下抛出 下标超出范围 错误 Sub This x Sheet1 y D3 MsgBox x Range y Value End Sub This is 我的项目资源管理器的示例 https i st
  • for 循环范围内的初始值设定项列表

    我有从单个超类型派生的不同类型的对象 我想知道使用中有没有什么缺点std initializer在 for 循环范围内列出 如下所示 for auto object std initializer list object1 object2

随机推荐

  • CentOS 7 安装 node.js

    1 下载node js安装包 打开 https nodejs org zh cn download 链接 xff0c 选择对应的版本进行下载 xff0c 这里选择16 14 2 可以下载到本地 xff0c 然后传到Linux系统中 xff0
  • Linux安装Nginx

    1 下载nginx 进入 http nginx org en download html 网址 分别有 Mainline version xff08 主线版 开发版 xff09 Stable version xff08 稳定版 xff09
  • 使用nginx进行负载均衡

    1 nginx负载均衡介绍 nginx应用场景之一就是负载均衡 在访问量较多的时候 xff0c 可以通过负载均衡 xff0c 将多个请求分摊到多台服务器上 xff0c 相当于把一台服务器需要承担的负载量交给多台服务器处理 xff0c 进而提
  • 普通人的第一个Linux发行版-安装Deepin20.5

    1 Deepin系统闲聊 Deepin是Linux系统的发行版之一 Deepin其实在国内已经有相当长的发展时间了 xff0c 个人认为 xff0c 在国内的Linux发行版中 xff0c Deepin可以不夸张的说就是龙头 xff0c 例
  • Deepin20.5安装JDK8

    1 下载OpenJDK Deepin20 5下安装jdk 这里使用AdoptOpenJDK xff0c 版本8 虚拟机使用HotSplot 首先进入AdoptOpenJDK官网进行下载 xff0c 官方地址为 xff1a https ado
  • Deepin20.5安装maven

    1 前置依赖 安装Maven之前 xff0c 首先需要安装JDK xff0c 如何从Deepin中安装JDK xff0c 可以参考 xff1a Deepin20 5安装JDK8 2 下载Maven 官网最新版本已经变为3 8 xff0c 这
  • Python不智能的聊天机器人

    上代码 xff01 亲测好用 本文当做Git库 xff0c 经常更新 xff01 2022 08 17 V0 1 39 39 39 pyinstaller使用方法 home leopader local bin pyinstaller i
  • 厌倦了各种app推送广告?用RSS来订阅自己想看的内容吧

    前言 现在是2022年 xff0c 大数据加上信息大爆炸 xff0c 让各种资讯类App已经到了满天飞的地步 微博 头条 抖音 B站 公众号等等等 xff0c 数之不尽 xff0c 一会看看这个 xff0c 一会看看那个 xff0c 应用来
  • linux安装极狐gitlab

    1 官网寻找安装方式 不管我们使用任何软件 xff0c 最靠谱的方式就是查看官方文档 gitlab提供了相应的安装文档 xff0c 并且有对应的中文文档 地址如下 xff1a https gitlab cn install 我在这里以Cen
  • linux安装jenkins

    1 官网寻找安装方式 进入到jenkins官网 xff0c 找到对应的下载页面 xff1a https www jenkins io download 根据自己系统还有想要使用的版本 xff0c 进行选择即可 这里我们使用CentOS作为示
  • 使用jenkins实现自动化部署springboot应用

    1 前置准备 这里代码仓库使用gitlab 在介绍如何通过gitlab和jenkins进行自动化部署之前 xff0c 需要先安装完成gitlab以及jenkins 两种程序的安装方式以及相关配置可以参看以下内容 xff1a linux中安装
  • 申请免费的国产泛域名证书

    1 申请免费泛域名证书 云服务商提供的免费证书一般都是单独域名证书 xff0c 对于泛域名 xff08 也可以称为子域名 通配符域名 xff09 支持的较少 如果想要使用免费的泛域名 xff0c 则需要付费购买或者使用Let s Encry
  • QT入门初学者——如何新建一个工程项目(详细)

    本文讲的是如果用QT新建一个项目和打开现有的项目 我这里的QT使用的是QT4 xff0c 如果需要安装软件的话去我的后序其他文章里找 xff0c 可以直接下载安装使用 第一步 xff0c 先打开QT程序 打开之后的页面是这样的 xff0c
  • QT入门初学者——如何更改Widget窗口左上角标题的图标

    运行出来之后的界面左上角都是默认窗口的属性值 xff0c 今天教大家怎么个性化设置 首先 xff0c 先打开自己的UI界面 xff0c 鼠标选中Widget xff08 QWidget xff09 在后下角属性调整里面找到下列两个属性值 x
  • QT入门初学者——如何创建和使用资源文件Resource(详细)

    使用QT创建资源文件 xff0c 可以对UI设计 窗口图标等一些需要用到图片或GIF图的地方 首先先拥有一个基本的QT项目 xff0c 可以是全新创建的 xff0c 也可以是现有的 xff0c 打开该项目 点击File gt New Fil
  • C语言题目:HDU - 1408 盐水的故事

    题目描述 挂盐水的时候 xff0c 如果滴起来有规律 xff0c 先是滴一滴 xff0c 停一下 xff1b 然后滴二滴 xff0c 停一 下 xff1b 再滴三滴 xff0c 停一下 xff0c 现在有一个问题 xff1a 这瓶盐水一共有
  • 使用Android Studio创建第一个程序Hello word超详细

    首先 xff0c 打开Android Studio软件 xff0c 双击打开 打开后的页面如下所示 xff0c 点击第一个新建一个项目 点开之后如图所示 xff0c 点击Phone and Tablet xff0c 这个就是手机和平板适用
  • 让我们和机器一起聊天

    Python大法好 xff01 让我们做一个可以聊天的玩意 xff01 Python可以干好多事 xff0c 两天前 xff0c 我有一个想法 xff1a 和电脑交流 我第一个想法就是打造一个字典数据集 xff0c 获取你的输入 xff0c
  • 团体程序设计天梯赛-练习集-001 Hello World (5 分)

    这道超级简单的题目没有任何输入 你只需要在一行中输出著名短句 Hello World 就可以了 输入样例 xff1a 无 输出样例 xff1a Hello World include lt stdio h gt int main void
  • C++20新特性—range(一)

    1 range的概念 Ranges 实际上可理解为一个接口规范 xff08 C 43 43 20中的concept xff09 xff0c 它针对集合 xff0c 提供begin 和end 两个方法 xff0c 返回一个指示类 xff08