C++ 20新特性之Ranges

2024-06-10 11:12
文章标签 c++ 特性 20 ranges

本文主要是介绍C++ 20新特性之Ranges,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

💡 如果想阅读最新的文章,或者有技术问题需要交流和沟通,可搜索并关注微信公众号“希望睿智”。

为什么要引入Ranges

        在C++ 20之前,我们处理容器和迭代器时,通常需要使用一系列的算法和复杂的迭代器操作。这不仅繁琐,而且很容易出错,尤其是对于复杂的算法组合。C++ 20引入Ranges的原因主要是为了提高标准库的表达力、效率和代码的可读性,以及简化序列操作的复杂度。

        任何可以被迭代的对象都可以视为Ranges,包括标准库容器(比如:vector、list、map等)、数组,甚至是由函数生成的连续或非连续元素序列。Ranges提供了一组函数和操作符,让我们能够以更加函数式的方式处理容器中的数据。这些函数和操作符通常与现有的STL算法具有相同的功能,但它们更简洁,也更易于使用。

Ranges视图

        View是Ranges的核心,相当于一个透镜,通过它可以观察Ranges的不同视图。视图是一个对数据的非拥有、可能懒加载的引用,它不会复制或修改原始数据,而是提供了一种方式来查看或处理这些数据。这使得我们可以在不修改原始数据的情况下,对数据进行过滤、映射、切片等各种复杂的操作。

        在下面的示例代码中,我们使用views::filter来过滤出一个整型容器中的偶数,得到了视图viewEven。最后,我们使用ranges::for_each来遍历视图viewEven进行输出。

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
using namespace std;int main()
{vector<int> vctNum = {1, 2, 3, 4, 5};auto viewEven = vctNum | views::filter([](int n) { return n % 2 == 0; });// 输出: 2 4ranges::for_each(viewEven, [](int n) { cout << n << ' '; });return 0;
}

Ranges适配器

        Ranges适配器负责接收一个输入Range(或多个输入Ranges),并根据适配器定义的规则转换或处理这些输入,最终产生一个新的Range。这个过程通常是懒惰执行的,意味着数据仅在实际访问时才会被处理。常见的适配器有如下几种。

        转换适配器(Transform Adapter):比如ranges::view::transform,它接受一个函数或Lambda,对输入Range中的每个元素应用该函数,并生成一个新元素。

        过滤适配器(Filter Adapter):比如ranges::view::filter,它根据提供的谓词筛选出符合条件的元素,丢弃不符合条件的元素。

        取前N个元素适配器(Take Adapter):比如ranges::view::take,仅取Range的前N个元素,这对于处理有限制的数据流非常有用。

        丢弃前N个元素适配器(Drop Adapter):比如ranges::view::drop,丢弃Range的前N个元素,然后返回剩余的元素。

        合并适配器(Concatenate Adapter):比如ranges::view::join,用于将一系列Range(通常为Range的Range)连接成一个单一的Range。

        切片适配器(Slicing Adapter):比如ranges::view::slice,可以取出Range的一个子区间,类似于数组的切片操作。

        在下面的示例代码中,我们使用转换适配器将原始的vctNum转换成了一个视图,这个视图中每个元素的值为vctNum中每个元素的平方。最后,我们使用ranges::for_each来遍历视图viewSquared进行输出。注意:views::transform并不会修改原始的vctNum,而是产生了一个新的Range视图。

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
using namespace std;int main()
{vector<int> vctNum = {1, 2, 3, 4, 5};auto viewSquared = vctNum | views::transform([](int n) { return n * n; });// 输出: 1 4 9 16 25ranges::for_each(viewSquared, [](int n) { cout << n << ' '; });return 0;
}

Ranges算法

        Ranges还提供了一组与STL算法类似的算法,这些算法可以直接在Range上操作,而无需显式地使用繁琐的迭代器。在下面的示例代码中,我们使用std::ranges::find来在vctNum中查找一个元素。

#include <iostream>
#include <vector>
#include <ranges>
#include <format>
using namespace std;int main()
{vector<int> vctNum = {1, 2, 3, 4, 5};auto it = ranges::find(vctNum, 2);if (it != vctNum.end()){cout << format("found {}", *it) << endl;}else{cout << "not found" << endl;}return 0;
}

管道操作符

        管道操作符,也就是“|”符号,是C++ 20中一个重载过的操作符。在Ranges库中,它用于连接一系列的操作,形成一个数据处理的管道。这意味着,数据可以从一个操作流向下一个操作,每个环节只关注处理数据,而不需要关心数据的来源和去向。当我们将numbers | ranges::view::...这样的表达式放在一起时,意味着我们正在创建一个处理numbers集合的管道,其中...代表具体的View操作。

        在下面的示例代码中,我们首先过滤出偶数,然后计算它们的平方,这展示了ranges的简洁性和表达力。通过这样的管道表达式,C++程序员能够以一种声明性的方式写出高效且易于理解的代码,特别适合进行数据处理和分析任务。

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
using namespace std;int main()
{vector<int> vctNum = {1, 2, 3, 4, 5, 6};auto viewResult = vctNum | views::filter([](int x) { return x % 2 == 0; }) | views::transform([](int x) { return x * x; });// 输出:4 16 36ranges::for_each(viewResult, [](int x) { cout << x << " "; });return 0;
}

这篇关于C++ 20新特性之Ranges的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1048001

相关文章

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元