C++ 20 Range

2023-05-16

简单理解为:封装了begin(),end()这一对迭代器的对象。range的抽象级别更高,具有更多好处。
1)避免繁琐

std::for_each( begin(v), end(v),  //迭代器,书写繁琐,易错
    []( auto i ){ std::cout << i ; } 
) ;

std::ranges::for_each( v,    //range写法
    []( auto i ){ std::cout << i ; }
) ;

2)函数式编程

for ( auto i : iota( 1, 10 ) | reverse )  //描述目的
    std::cout << i ;

for ( auto i = 10 ; i>0 ; --i )  //描述算法步骤
    std::cout << i ;
#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
 
   std::vector<int> evenNumbers;
   std::copy_if(begin(numbers), end(numbers), 
         std::back_inserter(evenNumbers), [](int n){ return n % 2 == 0; });
 
   std::vector<int> results;
   std::transform(begin(evenNumbers), end(evenNumbers), 
         std::back_inserter(results), [](int n){ return n * 2; });
 
   for (int n : results)
   {
      std::cout << n << ' ';
   }
}

STL算法的缺点:各自为政,粘合在一起的代价大。现在用range重写:

std::vector<int> numbers={1,2,3,4,5};
auto v = numbers | ranges::view::filter([](int n){ return n % 2 == 0; })
                 | ranges::view::transform([](int n) { return n * 2; });
for(auto i : v) std::cout << i ;

管道符|方式的等价物是C语言方式:

std::vector<int> numbers={1,2,3,4,5};

filter_view f( numbers, [](int n){ return n % 2 == 0; } ) ;
transform_view t( f, [](int n) { return n * 2; } ) ;

for ( auto n : t )
    std::cout << n ;

Range库提供很多算法,能代替STL。下文代码片段统一需要:

#include <vector>
#include <list>
#include <map>
#include <iostream>
#include <string> 
#include <range/v3/all.hpp>
int main()
{    
    auto concat = [](std::string a, int b){ 
                      return std::move(a) + '-' + std::to_string(b); 
                  };

    auto const v = std::vector<int> {1,2,3,4,5};
    
    //累积{1,2,3,4,5},变成1-2-3-4-5
    auto rng = ranges::accumulate(v | ranges::views::drop(1), std::to_string(v[0]), concat);
    
    //等价的“手写”代码
    std::string result = std::to_string(v[0]);
    for(auto ite = std::next(v.begin()); ite!=v.end(); ++ite){
        result = concat(result,*ite );
    }
    std::cout << result ;
}
int main()
{    
    std::vector<int> v {6,4,1,8,3};  
    //copy vector到cout的经典代码 
    ranges::copy(v, ranges::ostream_iterator<>(std::cout, " "));

    std::vector<int> v2;
    ranges::copy(v, ranges::back_inserter(v2));
}
int main()
{    
    auto v = std::vector<int> {6,7,1,3};
    std::vector<int> result = ranges::sort(v); // [1,3,6,7] 
}
int main()
{    
    auto const v = std::vector<int> {1,2,3,4,5};
    //把实体view化
    auto rng = v | ranges::views::all; // [1,2,3,4,5]
    std::cout << rng ;  //std::vector是不能与cout结合的,但是view可以
    //std::cout << ranges::views::all(v);
}
int main()
{    
    auto const cities = std::vector<std::string>  {"New York", "Moscow", "Berlin", "Beijing" };
    auto const population = std::vector<double>   { 8.6,        11.9,     3.5                };
    auto const country = std::vector<std::string> {"US",       "RU",      "DE"               };
    
    //zip操作
    auto rng = ranges::views::zip(cities, population, country);

    //结构化绑定
    for (auto&& [first, second, third] : rng) 
         std::cout << first << ", " << second << "," << third << '\n';
}
int main()
{    
    auto const v = std::map<int,char>{ {1,'A'},{2,'B'},{3,'C'},{4,'D'},{5,'E'} };

    //通用的元素删除
    auto rng = v | ranges::views::remove_if( [](auto p) { return p.first%2==0; } );
    
    for (auto[k,v]:rng){ std::cout << k << " " << v << std::endl; }
}
int main()
{    
    std::string s1 = "hello ";
    std::string s2 = "world!";
    
    //concat是操作多个独立的range对象
    auto rng = ranges::views::concat(s1,s2); 
    std::cout << rng << std::endl;

    auto const v = std::vector<std::vector<int>>{ {1,3}, {11,13,15}, {25},};
    
    //join操作的是一个range,这个range的元素是range(简称range的range)
    auto rng2 = v | ranges::views::join; // [1,3,11,13,15,25]
    std::cout << rng2 << std::endl;
}
int main()
{    
    std::string sentence = "hello world!";
    auto rng = sentence | ranges::views::split(' ') | ranges::to<std::list<std::string>>; 
    for (auto str : rng){
        std::cout << str << std::endl;
    }
}

最后这个split view,需要物化后才能直接遍历,这是很多初次接触到split适配器的人忽视的地方。
参考:https://www.walletfox.com/course/quickref_range_v3.php

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

C++ 20 Range 的相关文章

随机推荐

  • BSS段

    深入理解计算机系统 bss段 xff0c data段 text段 堆 heap 和栈 stack 1 关于BSS段的大小 2 1 BSS段中的内容 2 2 BSS段在加载运行前的处理 3 3 BSS段的作用 3 4 代码优化对BSS段的影响
  • Java 比较两个List对象差集(根据某一值)

    很多都是比较List lt String gt 的 xff0c 和自身业务不符 xff0c jdk1 8 新特性强大的Stream API xff0c 具体是什么方法 xff0c 什么作用自行百度 xff0c 复制粘贴可以解决问题就OK 4
  • Windows10 安装Redis(图文教程)

    Redis xff08 Remote Dictionary Server xff0c 即远程字典服务 xff0c 是一个开源的使用ANSI C语言编写 支持网络 可基于内存亦可持久化的日志型 Key Value数据库 一 下载redis客户
  • e17 enlightenment 介绍及配置

    为什么要有一个窗口管理器 为什么一定要有一个桌面背景 xff0c 甚至是标题栏 或是如果把一个应用程序如firefox当成桌面背景行不行 桌面能不能再快一点 我不想把资源浪费在那些用不到的地方 Linux那么多虚拟桌面 xff0c 为什么我
  • Vim: Warning: input is not from a terminal 后退出 vim 终端异常

    Vim Warning input is not from a terminal 后退出 vim 终端异常 今天执行了如下命令调用 vi 来打开 find 搜索到的文件 xff1a longyu 64 longyu pc span clas
  • UNPV2 学习:Posix Message Queues

    文章目录 特点消息队列的释放mq notify 函数mq notify 使用信号通知消息到达直接在信号处理函数中调用 mq notify 与 mq receive 函数来接收数据在信号处理函数中设置标志在程序主逻辑中调用 mq notify
  • VMware ESXI虚拟机磁盘在线扩容后fdisk -l 找不到问题解决

    VMware ESXI虚拟机磁盘在线扩容后fdisk l 找不到问题解决 在VMware ESXI终端页面为虚拟机新增磁盘后 xff0c 进入虚拟机执行fdisk l 找不到新增的盘 重启系统肯定是可以解决的 xff0c 但是机器有在跑测试
  • go调用python

    安装 安装python和go的环境 xff0c 在debian和ubuntu系统上 xff0c 还要sudo apt install python all dev安装sudo apt get install pkg config安装go g
  • C++ 20 Concept 语法

    requires expression 一种表达式 xff0c 它很像一个lambda表达式 xff0c 一个未命名元函数 例如 xff1a requires int a int b a 43 b 其中 xff1a xff08 xff09
  • 带你一步步破解Android微信聊天记录解决方案

    哪个小可爱在偷偷的看我 前言 最近公司需要做个内部应用 xff0c 需求有通话并录音上传服务器 xff0c 微信聊天记录上传服务器 xff0c 我擦 xff0c 竟然要做严重窃取隐私的功能 xff0c 一万个草泥马奔腾而来 xff0c 于是
  • 51单片机定时器初值的计算

    什么是时钟周期 xff1f 什么是机器周期 xff1f 什么是指令周期 xff1f 时钟周期 时钟周期也称为振荡周期 xff0c 定义为时钟脉冲的倒数 xff08 可以这样来理解 xff0c 时钟周期就是单片机外接晶振的倒数 xff0c 例
  • 计算机操作系统之系统调用

    目录 x1f4a8 什么是系统调用 xff0c 有何作用 xff1f x1f4a8 系统调用与库函数的区别 x1f4a8 系统调用背后的过程 x1f4a8 总结 我们将带着以下问题去学习什么是系统调用 什么是系统调用 xff0c 有何作用
  • Python简易逻辑运算

    1 逻辑运算符 逻辑运算在编程中是十分重要的组成部分 xff0c 除了布尔值外 xff0c 还有其他用于逻辑运算的运算符 and 与 or 或 not 非 and连接的条件判断必须前后全部成立结果才能成立 xff08 所有条件True才输出
  • RCE漏洞之绕过

    文章目录 花括号斜杠空格过滤一些命令分隔符黑名单绕过拼接绕过编码绕过单引号和双引号绕过利用Shell 特殊变量绕过linux中直接查看文件内容的工具文件构造 花括号 在Linux bash中还可以使用 OS COMMAND ARGUMENT
  • 调用windows系统动态库实现wifi连接及问题

    有个项目是c 做的 xff0c 有个需求是程序启动自动连接指定wifi xff0c 想到windows有个系统库支持 xff0c 就用c 43 43 调的系统库 xff0c 然后c 再调c 43 43 封装好的接口 xff0c 比较简单 x
  • ffmpeg编译时cmp: command not found的问题

    执行安装 pacman S diffutils 参考 xff1a https stackoverflow com questions 18152168 using cygwin for ffmpeg build error cmp comm
  • 关于vs2013弹出“正在初始化模板“的问题

    此处有标题 昨天想在vs2013里配置python的编译环境 xff0c 于是在网上找了资源来下载 xff0c 但是由于中途出了一点意外 xff0c 配置过程中断了 xff0c 再等我回来想要新建项目的时候 xff0c 就弹出来这个框框 x
  • C++异常和C++11标准

    异常 异常概念 xff1a 程序中可预料但无法避免的错误 异常处理概念 xff1a 从发生异常的地方开始终止 xff0c 不再进行正常的流程 xff0c 去转而执行特定的异常处理流程 关键字 xff1a try try块 xff0c 受监控
  • linux下安装sl

    在root用户下哦 yum install sl 这里会提示 No package sl available 我们要安装一个wget yum install wget 中间一路yes 提示出现Complete即为安装成功 下一步用wget安
  • C++ 20 Range

    简单理解为 xff1a 封装了begin xff0c end 这一对迭代器的对象 range的抽象级别更高 xff0c 具有更多好处 1 xff09 避免繁琐 std for each begin v end v 迭代器 xff0c 书写繁