C++20 Ranges 完全指南
C++20 Ranges 完全指南

C++20 Ranges 完全指南:懒惰计算、链式操作与函数式编程范式

在本篇文章中,我们将深入介绍 C++20 引入的 ranges 库,包括 std::ranges 算法、std::views 视图、链式组合技巧、容器转换等高级技巧,助你掌握这一现代 C++ 中的函数式利器。


什么是 Ranges?

传统的 C++ STL 算法,如 std::sortstd::copy 等,通常需要传入 begin()end()。而 ranges 则基于“范围对象”操作容器,具备以下优势:

  • 更简洁:支持直接传容器。

  • 可组合:支持管道操作 | 实现链式风格。

  • 惰性计算:views 不立即生成结果,节省资源。

  • 函数式编程风格:更接近 Python、Rust 等现代语言的风格。


基础使用:ranges 算法

C++20 在 <algorithm> 中添加了 ranges 版本的 STL 算法(位于 std::ranges:: 命名空间中):

 1#include <vector>
 2#include <ranges>
 3#include <algorithm>
 4#include <iostream>
 5
 6int main() {
 7    std::vector<int> v{5, 1, 3, 2};
 8
 9    std::ranges::sort(v);  // 排序
10    std::ranges::for_each(v, [](int x){ std::cout << x << " "; });  // 输出:1 2 3 5
11}

几乎所有常用算法都存在 ranges 版本:sortfindcopyfor_eachuniqueremove 等。


Views:懒惰计算视图

std::views 提供一系列可组合的“视图”操作,它们不会立即计算结果,而是在访问元素时才执行。

常见视图(std::views::):

视图功能说明
filter过滤元素
transform元素映射(变换)
take(n)取前 n 个元素
drop(n)跳过前 n 个元素
reverse反转序列
iota(a, b)类似 Python 的 range(a, b)
1std::vector<int> v{1, 2, 3, 4, 5, 6};
2
3auto r = v 
4    | std::views::filter([](int x){ return x % 2 == 0; })
5    | std::views::transform([](int x){ return x * x; });
6
7for (int x : r) std::cout << x << " ";  // 输出:4 16 36

链式组合与管道操作符

使用 | 管道符可以组合多个 views 操作,形成惰性计算的管道链,避免中间变量:

1auto r = vec
2    | std::views::filter(...)
3    | std::views::transform(...)
4    | std::views::take(10);

这种方式不仅可读性强,还能高效处理大规模数据。


常见视图与范例

🎯 views::filter

1auto even = vec | std::views::filter([](int x){ return x % 2 == 0; });

🔁 views::transform

1auto square = vec | std::views::transform([](int x){ return x * x; });

➕ 链式组合示例

1auto result = vec
2    | std::views::filter([](int x){ return x > 3; })
3    | std::views::transform([](int x){ return x * 10; })
4    | std::views::take(3);

🔢 views::iota

1for (int x : std::views::iota(1, 6)) {
2    std::cout << x << " ";  // 1 2 3 4 5
3}

结果转换为容器

因为 views 是惰性序列,若需要结果容器(如 vector),可以手动转换:

✅ C++20 写法

1std::vector<int> out(r.begin(), r.end());

✅ C++23 更方便:

1auto out = r | std::ranges::to<std::vector>();

若使用 C++20,可以自己写一个 to_vector() 工具函数进行转换。


完整案例演示

示例:提取偶数并平方,保存为 std::vector

 1#include <vector>
 2#include <ranges>
 3#include <iostream>
 4
 5int main() {
 6    std::vector<int> data{1,2,3,4,5,6,7,8};
 7
 8    auto r = data
 9        | std::views::filter([](int x){ return x % 2 == 0; })
10        | std::views::transform([](int x){ return x * x; });
11
12    std::vector<int> result(r.begin(), r.end());  // 结果为 {4, 16, 36, 64}
13
14    for (int x : result) std::cout << x << " ";
15}

拓展库推荐

如果你想使用更多 views(如 zip, enumerate, chunk),推荐以下库:

  • range-v3:C++20 ranges 的鼻祖,支持更多视图操作。

  • cppcoro:提供协程风格的 ranges。


总结

特性说明
ranges:: 算法替代传统 STL 算法,支持容器直接传参
views:: 视图支持懒惰链式处理,性能更优
管道 `` 操作
容器转换可通过迭代器或 ranges::to 转换为 vector 等

最后修改于 2025-07-08 18:57