C++ range

2023-05-16

C++20 引入了 range 来简化对元素序列的处理(可以省略掉许多的循环遍历)。

1. range 和 view

range

range concept 通过提供一个迭代器以及一个哨兵来表示一个元素范围,以允许对某个类型进行遍历。

template<class T>
concept range = requires(T& t) {
  ranges::begin(t);
  ranges::end(t);
};

如,vector 就是一个 range:

std::vector<int> vec{ 1, 2, 3 };

auto it1 = std::ranges::begin(vec);
auto it2 = std::ranges::end(vec);

view

view 是一个 range,且具有常数时间复杂度的的拷贝、移动和赋值操作(如,直接操作一对迭代器、或使用生成器来按需生成元素)。

template<class T>
concept view = ranges::range<T> && std::movable<T> && ranges::enable_view<T>;

template<class T>
inline constexpr bool enable_view =
    std::derived_from<T, view_base> || /*is-derived-from-view-interface*/<T>;

如,可通过 iota 来创建一个 view,类似于 Python 中的 range:

auto v1 = std::views::iota(1);		// [1, +inf)
auto v2 = std::views::iota(1, 10);	// [1, 10)

for (int i : v2)
{
    std::cout << i << ' ';
}

2. 范围工厂

会创建一个 view。

iota:创建一个不断递增的元素序列,可以是有界的,也可以是无界的。

#include <iostream>
#include <ranges>

int main()
{
	auto v1 = std::views::iota(10);		// [10, +inf)
	auto v2 = std::views::iota(1, 10);	 // [1, 10)

	for (int i = 0; i < 10; i++)
	{
		std::cout << v1[i] << ' ';
	}
	std::cout << '\n';

	for (int i : v2)
	{
		std::cout << i << ' ';
	}
}
10 11 12 13 14 15 16 17 18 19
1 2 3 4 5 6 7 8 9

istream_view:对某个输入流不断地应用 operator >>,从而获得一系列的元素。

#include <iostream>
#include <sstream>
#include <ranges>

int main()
{
	std::istringstream nums("1.1 2.2 3.3\t4.4\n5.5");
	auto v = std::ranges::istream_view<float>(nums);

	for (float f : v)
	{
		std::cout << f << ", ";
	}
}
1.1, 2.2, 3.3, 4.4, 5.5,

3. 范围适配器

接受一个 range,对其执行某些操作后,返回结果 view。

counted:从指定位置开始获取 n 个元素。

std::vector<int> vec{ 1, 2, 3, 4, 5, 6, 7 };

for (int i : std::views::counted(vec.begin() + 1, 3))
{
    std::cout << i << ' ';
}
2 3 4

drop:丢弃 range 中的前 n 个元素。

int nums[] = { 0, 1, 2, 3, 4, 5, 6 };

for (int i : std::views::drop(nums, 3))
{
    std::cout << i << ' ';
}
3 4 5 6

elements:获取第 n 列元素。

注:view 中的元素需要是 tuple-like 的。

std::vector<std::tuple<int, int, int>> vecs
{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
};

for (int i : std::views::elements<1>(vecs))
{
    std::cout << i << ' ';
}
2 5 8

filter:对 range 进行过滤,只保留符合条件的元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };
auto even = [](int i)
{
    return i % 2 == 0;
};

for (int i : std::views::filter(nums, even))
{
    std::cout << i << ' ';
}
0 2 4

join:合并多个 range。

std::vector<int> vec1{ 1, 2, 3 };
std::vector<int> vec2{ 4, 5, 6 };
std::vector<std::vector<int>> vecs{vec1, vec2};

for (int i : std::views::join(vecs))
{
    std::cout << i << ' ';
}
1 2 3 4 5 6

reverse:反转 range 中的元素。

const int a[] = { 1, 2, 3, 4, 5, 6, 7 };

for (int i : std::views::reverse(a))
{
    std::cout << i << ' ';
}
7 6 5 4 3 2 1

split:按指定的元素分割 range。

std::vector<int> vec{ 1, 2, 3, 4, 5, 6, 7 };

for (const auto& v : std::views::split(vec, 4))
{
    for (int i : v)
    {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}
1 2 3
5 6 7

take:获取 range 中的前 n 个元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };

for (int i : std::views::take(nums, 3))
{
    std::cout << i << ' ';
}
0 1 2

transform:对 range 中的每个元素执行指定的转换操作,转换操作的返回值就是结果 view 中的元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };
auto square = [](int i)
{
    return i * i;
};

for (int i : std::views::transform(nums, square))
{
    std::cout << i << ' ';
}
0 1 4 9 16 25

4. 管道运算符

如果 C 是一个范围适配器闭包对象R 是一个可以转换为 view 的 range,则 C(R) 等价于 R | C

范围适配器闭包对象包括:一元范围适配器(只接受一个参数)、绑定了余下参数的多元范围适配器(只留下第一个参数未指定)和 R | C 的返回值。

int nums[] = { 0, 1, 2, 3, 4, 5 };

auto even = [](int i)
{
    return i % 2 == 0;
};

// 先过滤,然后反转过滤得到的元素
for (int i : nums | std::views::filter(even) | std::views::reverse)
{
    std::cout << i << ' ';
}
4 2 0

以下等价:

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

C++ range 的相关文章

随机推荐

  • 原生PHP7操作mongodb4

    Mongodb安装篇 CentOS7 Mongodb4 0 1 https blog csdn net gaokcl article details 83587077 Mongodb 配置用户 https blog csdn net gao
  • Linux命令行卡住不显示命令的解决方法

    1 问题描述 在使用终端工具如Xshell iTerm2时登录到linux服务器后 xff0c 在运行某些程序出错时 xff0c 有的时候会出现命令行卡住不显示命令的情况 2 解决方案 在命令行中输入reset xff0c 再回车即可 xf
  • word文档转换为md文档

    1 xff0c 安装软件 官网 xff1a Pandoc Installing pandoc 2 xff0c 打开cmd xff0c 切换到word文件所在的目录 这个不会可以自行百度不难 3 xff0c 在根文件目录下输入如下这行代码 p
  • docker 的 --rm与docker rm 的区别

    Dockerfile里的VOLUME和docker run v path的时候挂载容器的挂载点效果是一致的 会在宿主机 var lib docker volumes目录生成随机目录 发现 rm不单单是删除掉容器 xff0c 还会删掉挂载点的
  • jenkins 面试题

    1 jenkins是什么 Jenkins是一个开源的 可扩展的持续集成 交付 部署 xff08 软件 代码的编译 打包 部署 xff09 的基于web界面的平台 允许持续集成和持续交付项目 xff0c 无论用的是什么平台 xff0c 可以处
  • ubuntu18.04安装llvm-9 clang-9

    低版本的ubuntu只能采用编译安装的方式 xff0c 高版本的ubuntu可以采用如下方式安装 span class token keyword echo span deb http apt llvm org xenial llvm to
  • linux 下conda环境的配置

    1 安装 anaconda 3 0 下载安装包 xff1a span class token function wget span https repo continuum io archive Anaconda3 5 0 0 Linux
  • Linux 下如何添加一个普通用户,并给予用户root权限

    1 添加用户 xff0c 首先用adduser命令添加一个普通用户 xff0c 命令如下 adduser test1 添加一个名为tommy的用户 span class token function passwd span test1 修改
  • 不使用密码向github提交代码

    每次向github提交代码时都要输入用户名密码 xff0c 太麻烦了 xff0c 影响效率 解决方法 xff1a 1 在命令行中输入 span class token function git span config global cred
  • centos7系统安装好后远程连接执行命令很卡

    centos7系统安装好后 xff0c 远程连接也ok 但远程连接之后执行命令很卡 xff0c 这个问题可能是macaddr导致的 xff0c 我们要检查一下macaddr是否和其他的服务器相同 MACADDR 61 其中 以AA BB C
  • UESTC 1170 红蓝点对

    UESTC 1170 是个变异的最近点对题目 xff0c 用分治策略和计算几何做的话好像会超因为时间上是1000ms xff0c 下面这个贪心做法是看了别人的博客知道的 处理红点到原点的距离然后根据距离排序 xff0c 蓝点一样 xff0c
  • CDH环境下HDFS权限问题

    CDH环境下Hadoop平台最高权限用户是hdfs xff0c 属于supergroup组 默认HDFS会开启权限认证 xff0c 所以操作时 xff0c 需要将root用户切换到hdfs用户 xff0c 否则会报错 问题 xff1a or
  • 手动开启/关闭HDFS的safemode(安全模式)

    在hadoop启动namenode的时候 xff0c 会启动安全模式 xff08 safemode xff09 xff0c 在该模式下 xff0c namenode会等待datanode向它发送块报告 xff08 block report
  • centos7 update gcc to 7.2

    centos7默认的gcc版本是4 8 xff0c 我们需要升级到7 2 安装gcc span class token function wget span https github com gcc mirror gcc archive r
  • centos7升级GLIBC后导致系统不能启动成功

    centos7 glibc2 13 glibc2 27 1 准备U盘系统盘 xff0c 系统要和原来的系统版本匹配 开机重启按F2进入BIOS xff0c 通过U盘启动系统 选择Rescue mode 2 接下来 xff0c 选择 Resc
  • 在Linux中如何运行C语言写的脚本

    目录 1 xff1a Linux下如何运行C语言脚本 2 xff1a 实例展示 1 xff1a Linux下如何运行C语言脚本 Linux别的系统我不知道是不是这个方法 xff0c 我是用的ubuntu的 xff0c 其他的我也没测试过 x
  • Linux——利用Shell脚本编写进度条

    初级版本 xff08 原始进度条 xff09 xff1a span class hljs shebang bin bash span span class hljs built in echo span span class hljs st
  • C语言的日期和时间函数的用法及相应示例

    1 xff0e 概念 在C C 43 43 中 xff0c 对字符串的操作有很多值得注意的问题 xff0c 同样 xff0c C C 43 43 对时间的操作也有许多值得大家注意的地方 下面主要介绍在C C 43 43 中时间和日期的使用方
  • xrdp完美实现Windows远程访问Ubuntu 16.04【包括多人桌面与原生桌面】

    多人桌面 1 安装xrdp sudo apt get install xrdp 2 安装vnc4server 我这里是安装xrdp的时候自动安装的 我看网上很多说是需要单独安装的 3 安装xfce4 sudo apt get install
  • C++ range

    C 43 43 20 引入了 range 来简化对元素序列的处理 xff08 可以省略掉许多的循环遍历 xff09 1 range 和 view range range concept 通过提供一个迭代器以及一个哨兵来表示一个元素范围 xf