C++ Ranges 教程
2025年5月17日 22:04
C++20 引入了 ranges(范围),这是一个强大且优雅的抽象,用于处理序列(如数组、vector 等)。相比传统的迭代器或旧式循环,Ranges 提高了代码的可读性、可组合性和性能。
什么是 Range?
在 C++20 中,range(范围) 是一种抽象,代表一个可以迭代的元素序列。它与 views(视图) 和 actions(操作) 如过滤、转换等配合使用非常自然。
传统循环 vs 基于 Range 的循环
#include <iostream> #include <vector> int main() { std::vector<int> v = {1, 2, 3, 4}; // 旧式循环 for (auto it = v.begin(); it != v.end(); ++it) std::cout << *it << ' '; // 基于范围的循环(C++11) for (auto x : v) std::cout << x << ' '; }
Range Views(视图)
View 是惰性的、可组合的范围操作。除非需要,一般不会复制数据。
Filter 和 Transform 示例
#include <iostream> #include <vector> #include <ranges> int main() { std::vector<int> v = {1, 2, 3, 4, 5, 6}; auto even_doubled = v | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * 2; }); for (int n : even_doubled) std::cout << n << ' '; // 输出:4 8 12 }
常见的 Views
View | 描述 |
---|---|
std::views::filter | 保留符合条件的元素 |
std::views::transform | 对每个元素应用函数 |
std::views::take(n) | 获取前 n 个元素 |
std::views::drop(n) | 跳过前 n 个元素 |
std::views::reverse | 反转范围 |
std::views::iota(a, b) | 生成从 a 到 b-1 的范围 |
使用 iota 和 reverse
#include <ranges> #include <iostream> int main() { for (int i : std::views::iota(1, 6) | std::views::reverse) std::cout << i << ' '; // 输出:5 4 3 2 1 }
组合视图操作
你可以使用管道符 |
流式地组合多个视图操作。
#include <vector> #include <ranges> #include <iostream> int main() { std::vector<int> v = {5, 10, 15, 20}; auto result = v | std::views::transform([](int x) { return x + 1; }) | std::views::filter([](int x) { return x % 2 == 0; }); for (int x : result) std::cout << x << ' '; // 输出:6 16 }
实用示例
1. 过滤偶数
#include <iostream> #include <vector> #include <ranges> int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6}; auto evens = numbers | std::views::filter([](int n) { return n % 2 == 0; }); for (int n : evens) std::cout << n << ' '; // 输出:2 4 6 }
2. 将奇数翻倍
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5}; auto doubled_odds = numbers | std::views::filter([](int n) { return n % 2 != 0; }) | std::views::transform([](int n) { return n * 2; }); for (int n : doubled_odds) std::cout << n << ' '; // 输出:2 6 10 }
3. 反转序列
int main() { std::vector<int> nums = {10, 20, 30}; auto reversed = nums | std::views::reverse; for (int n : reversed) std::cout << n << ' '; // 输出:30 20 10 }
4. 生成数值序列
#include <ranges> int main() { for (int i : std::views::iota(1, 6)) std::cout << i << ' '; // 输出:1 2 3 4 5 }
5. 获取前 N 个元素
int main() { auto infinite = std::views::iota(1); // 无限序列 auto first5 = infinite | std::views::take(5); for (int i : first5) std::cout << i << ' '; // 输出:1 2 3 4 5 }
6. 计算前 5 个奇数的平方和
#include <numeric> int main() { auto odd_squares = std::views::iota(1) | std::views::filter([](int x) { return x % 2 == 1; }) | std::views::transform([](int x) { return x * x; }) | std::views::take(5); int sum = std::accumulate(odd_squares.begin(), odd_squares.end(), 0); std::cout << "和 = " << sum << '\n'; // 输出:和 = 165 }
7. 判断是否所有元素都为正数
#include <ranges> #include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> nums = {1, 2, 3}; bool all_positive = std::ranges::all_of(nums, [](int n) { return n > 0; }); std::cout << std::boolalpha << all_positive << '\n'; // 输出:true }
8. 自定义管道函数
auto pipeline = [](const std::vector<int>& v) { return v | std::views::filter([](int x) { return x % 2 == 0; }) | std::views::transform([](int x) { return x * 10; }); }; int main() { std::vector<int> nums = {1, 2, 3, 4}; for (int x : pipeline(nums)) std::cout << x << ' '; // 输出:20 40 }
性能提示
- Ranges 是惰性的:仅在需要时才处理元素。
- 避免不必要的分配与复制。
- 适合处理大型数据或函数管道。
何时不适合使用 Ranges
- 在对性能极度敏感的内循环中,STL 抽象可能较慢。
- 当项目尚未迁移到 C++20。
参考资料
本文一共 415 个汉字, 你数一下对不对.扫描二维码,分享本文到微信朋友圈
The post C++ Ranges 教程 first appeared on 小赖子的英国生活和资讯.
相关文章:
- 简易教程: C++的智能指针 C++ 智能指针教程 C++ 中的智能指针提供了自动且安全的内存管理。它们通过 RAII(资源获取即初始化)机制,帮助开发者避免内存泄漏和悬空指针的问题,确保对象在生命周期结束时被正确释放。 本教程将介绍 C++ 中三种主要的智能指针: std::unique_ptr:独占式所有权 std::shared_ptr:共享式所有权 std::weak_ptr:非拥有式弱引用 1. std::unique_ptr unique_ptr 拥有独占所有权。一个资源只能被一个...
- 借助AI快速开源了三个小工具: 写代码越来越像做产品了, AI 真把我宠坏了(Vibe Coding) 程序员的未来?Vibe Coding + AI 一起上! 借助 AI 快速开源了三个小工具 最近,我利用 ChatGPT-4o 和 o4-mini 快速开发并开源了三个小工具。起因其实很简单——每次想转换 YAML/JSON 或进行...
- 被动收入之: 微博红包 今年开始重新经营我的微博帐号 drlai 收到两笔微信红包,应该是来自于官方的支持,150元(成功提现到支付宝)。虽然这不能持久,也没多少,但毕竟实现了零的突破,意义重大。 如果流量上来,内容创作者可能会接受到比较多的赞赏,这也是一个比较简单的变现方法。这也能作为一种被动收入,不过如果不是头部网红,可能杯水车薪,但如果你有好几个类似这样的,也能积少成多! 在用户中心,微博用户可以每天登陆手机微博APP打卡,获取点数和少量的红包钱(几分钱),积少成多! 微博做些小任务可获得积分和几分钱。聊胜于无。 微博的主要盈利模式 微博的主要盈利模式主要包括以下几个方面: 广告收入:微博的大部分收入来源于广告,尤其是品牌广告和效果广告。广告形式包括信息流广告(类似于推文广告)、热门话题广告、开屏广告和视频广告。品牌和企业可以利用微博庞大的用户群和社交互动来提升曝光率、推广品牌和产品。 会员服务:微博提供的VIP会员服务,用户可以支付订阅费用来享受更多的特权,比如个性化的主题、特有的表情包、私密权限设置等。这些会员服务主要面向个人用户,提升其社交体验。 直播和打赏:微博提供直播平台,用户可以通过购买虚拟礼物来支持主播,微博会从这些打赏中抽取一定比例的分成。此外,微博与内容创作者分成,通过内容付费、知识付费等形式变现。 增值服务:针对企业和大V(拥有大量粉丝的用户),微博还提供增值服务,如账号认证、粉丝数据分析、精准推送、推广和营销工具等。这些服务帮助企业提升营销效果,同时也增加了微博的收入来源。 电商和导流:微博上有大量的电商导流业务,尤其是和明星、网红的合作推广。微博用户在浏览社交内容时,可以直接跳转到商品购买链接,微博通过这种方式赚取导流佣金。 游戏联运:微博也会与一些游戏公司合作推出联合运营的游戏,微博负责推广和流量引入,用户充值或付费时,微博可以获得一部分的分成。 这些模式相结合,使得微博能够在广告市场、内容创作和电商等多个领域获利。...
- 换了个奥迪Q5大灯花了我1000英镑 我那辆奥迪Q5 SUV今年年检没通过,原因是左前车灯坏了,需要更换。车厂告诉我,光是订购零件就要700多英镑,加上人工费,总费用得1000英镑。但没办法,如果不修,车辆年检(MOT)就过不了,车也不能上路。 MOT是英国的机动车强制性安全检测(Ministry of Transport Test)的简称。 近侧前位置灯不工作 drl/位置灯集成(4.2.1(a)(ii)) Nearside Front Position lamp not working drl/position...
- 试用 Linkedin (领英) 高级帐号 (Premium) Linkedin (领英) 算是比较靠谱的职业社交网站, 在上面有很多猎头, 很多知名公司的HR 无时无刻在招人. 特别领英在被微软收购之后, 名气就变得大了许多. 领英是免费使用的, 但也有付费用户, 有给猎头的, 也有给想找工作的. 价格并不便宜, 对于想找工作的 Job...
- 步步高学生电脑上 Basic 编程语言 peek 用法示例 步步高学生电脑 是8位FC机的经典之作.它上面的BASIC有三个版本 1.0, 2.0 和 2.1 2.1 版本有个在线帮助,实际上是 help.cmd 1.0 是用 Esc 键退回到 DOS 的,...
- 《Steem 指南》之 justyy 在线工具与 API 系列 – Discord 机器人 Discord 聊天频道 Discord 原本是给游戏设计的, 但由于其功能多, 接口开放能力强, 使用的用户越来越多. 我们CN区也有一个Discord 频道, 加入地址为: https://discord.gg/7ctT3Xt 在网页里就可以加入 cnsteem 的大家庭了, 当然也可以下载手机APP或者桌面程序来加入...
- 你给SteemIt中文微信群拖后腿了么? 这年头不缺算法, 就缺数据. 这两天花了很多时间在整API上, 整完之后自己用了一下还觉得真是挺方便的. 今天就突然想看一看自己是否给大家拖后腿了, 于是调用每日中文区微信群排行榜单的API, 刷刷拿着 NodeJs 练手: 1 2 3 4 5 6...