在 C++20 标准中,std::ranges 库为 STL 容器提供了更直观、更表达式化的操作方式。相比传统的 std::begin / std::end + std::for_each 或手写循环,ranges 让代码更简洁、可读性更好,并且可以在编译期进行更多检查。下面从基本概念、常用视图与适配器、以及完整示例三个部分展开。
1. 基本概念
- 范围(Range):一对迭代器(
begin/end)或更抽象的range对象,满足std::ranges::range协议。标准容器、数组、std::span都是内置范围。 - 视图(View):对范围的懒加载、按需计算的包装。视图本身也是范围,但不持有实际数据。常见视图有
std::views::filter、std::views::transform、std::views::reverse等。 - 适配器(Adaptor):对视图进行组合、切片、组合的工具。适配器通常以
views::开头,使用管道符|进行链式调用。
2. 常用视图与适配器
| 视图/适配器 | 作用 | 示例 |
|---|---|---|
std::views::filter |
按条件筛选元素 | auto evens = v | std::views::filter([](int x){return x%2==0;}); |
std::views::transform |
对元素做一次变换 | auto squares = v | std::views::transform([](int x){return x*x;}); |
std::views::reverse |
反转顺序 | auto rev = v | std::views::reverse; |
std::views::take |
截取前 N 个元素 | auto first5 = v | std::views::take(5); |
std::views::drop |
跳过前 N 个元素 | auto after3 = v | std::views::drop(3); |
std::views::common |
将视图转换为常规范围(可随机访问) | auto common_v = v | std::views::common; |
3. 典型使用场景
3.1 过滤和变换
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector <int> nums{1,2,3,4,5,6,7,8,9,10};
// 取偶数并平方
auto processed = nums | std::views::filter([](int n){ return n%2==0; })
| std::views::transform([](int n){ return n*n; });
for (int x : processed) {
std::cout << x << ' '; // 输出 4 16 36 64 100
}
}
3.2 组合多种视图
auto result = nums | std::views::filter([](int n){ return n>5; })
| std::views::reverse
| std::views::take(3);
for (int x : result) std::cout << x << ' '; // 10 9 8
3.3 与 std::ranges::for_each
std::ranges::for_each(processed, [](int x){ std::cout << x << '\n'; });
3.4 计算总和与平均值
auto sum = std::reduce(std::execution::par_unseq, processed.begin(), processed.end(), 0LL);
auto avg = static_cast <double>(sum) / processed.size();
std::cout << "sum=" << sum << ", avg=" << avg << '\n';
4. 性能与注意事项
- 懒加载:除非被消耗,否则视图不会实际执行。使用
std::ranges::for_each或std::accumulate等终端操作时,视图才会被遍历。 - 执行策略:C++20 的
ranges与并行算法兼容,可在std::execution::par等策略下并行化。 - 常规范围:大多数标准容器已实现
std::ranges::range,但自定义容器需满足begin()/end(),并在std::ranges::range中提供特化。 - 视图复制:视图是轻量级对象,复制代价极低,但不持有数据;若需要持久化结果,请使用
std::vector或std::ranges::to.
5. 结语
std::ranges 在 C++20 中为容器操作提供了更接近自然语言的表达方式,既保留了 STL 的高效底层实现,又提升了代码可读性。无论是日常数据处理、算法实现,还是高性能并行计算,掌握 ranges 都能让你的 C++ 代码更优雅、更易维护。祝你编码愉快!