在 C++20 标准中,Range Views 提供了一个优雅的方式来对容器进行惰性操作。本文将介绍 Range Views 的核心概念、常用视图以及如何在实际项目中灵活运用。
1. Range 与 View 的区别
- Range:任何可遍历的数据序列(如 `std::vector `、`std::array`)。
- View:对 Range 的一层包装,提供延迟求值(惰性)以及函数式的链式操作。
例如std::views::filter、std::views::transform等。
2. 常用 View 示例
2.1 过滤(filter)
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector <int> data{1,2,3,4,5,6,7,8,9,10};
auto even = data | std::views::filter([](int x){ return x % 2 == 0; });
for(int n : even)
std::cout << n << ' '; // 输出: 2 4 6 8 10
}
2.2 转换(transform)
auto squared = data | std::views::transform([](int x){ return x * x; });
for(int n : squared)
std::cout << n << ' '; // 输出: 1 4 9 16 25 36 49 64 81 100
2.3 组合使用(pipeline)
auto processed = data
| std::views::filter([](int x){ return x > 5; })
| std::views::transform([](int x){ return x * 2; });
for(int n : processed)
std::cout << n << ' '; // 输出: 12 14 16 18 20
3. View 的惰性特性
与 std::vector 的显式拷贝不同,View 只在迭代时执行对应的 lambda。
这意味着在链式操作中不需要额外的中间容器,显著节省内存和时间。
4. 典型应用场景
- 数据流处理:对大数据集做多级筛选、映射后立即消费。
- 算法组合:在算法库中(如
std::ranges::for_each)直接使用 View。 - 接口简化:为 API 返回一个 View,使用者可自行决定何时遍历。
5. 与传统容器的协作
虽然 View 强大,但在某些情况下需要将结果转换为容器(如 std::vector)。
使用 std::ranges::to(在 C++23 之后正式支持)或手动构造即可:
auto vec = std::vector <int>{processed.begin(), processed.end()};
6. 性能小结
- 时间:相比显式循环,View 的惰性执行避免了多次遍历。
- 空间:无中间容器,显著降低峰值内存。
- 编译成本:模板化实现,编译期会生成专门的代码,运行时无额外开销。
7. 结语
C++20 的 Range Views 为程序员提供了一种极简且强大的数据处理方式。只需少量代码即可完成复杂的过滤、映射和组合操作,且在保持惰性和高效的前提下,提升代码可读性和可维护性。建议在日常项目中积极尝试,逐步替代传统循环+容器的写法。