ranges 和 views 简介
ranges
std::ranges
是 C++20 引入的一个新库,它将“范围(range)”作为一等公民。一个 range 是任何可以迭代的对象,比如数组、容器、生成器等。
它提供了类型安全、更简洁的算法接口,例如:
// C++98 风格
sort(vec.begin(), vec.end());
// C++20 风格
ranges::sort(vec);
无需再写 .begin()
和 .end()
,更安全、更直观。
views
std::views
是 Ranges 库中的核心组件。View 是一个不拥有数据的轻量级范围,它只是对原始数据提供一种“视图”或“投影”。
关键特性:
- 零拷贝:不复制原始数据。
- 延迟计算(Lazy Evaluation):只有在迭代时才真正执行操作。
- 可组合:多个视图可通过
|
链式组合。
管道运算符 |
C++20 重载了 |
运算符,用于将一个范围“传递”给一个视图适配器,形成链式调用。
auto result = data
| views::filter(pred)
| views::transform(f)
| views::take(5);
常用 Views 操作详解
1. filter
按条件筛选元素。
基本语法:
auto filtered = range | views::filter(predicate);
filtered
为一个名为filtered
的视图对象。predicate
是一个一元谓词函数(返回bool
),用于判断每个元素是否保留。
应用:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto filtered = vec | views::filter([](int x){ return x % 2 == 0; });
for (auto x : filtered)
cout << x << ' ';
作用:从一个容器中筛选出所有的偶数,并打印出来。
如果单纯只输出,以上代码可写为:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : vec | views::filter([](int x){ return x % 2 == 0; }))
cout << x << ' ';
结果:2 4 6 8
2. transform
映射/转换每个元素。
基本语法:
auto transformed = range | views::transform(func);
transformed
为一个名为transformed
的视图对象。func
接收一个元素,返回转换后的值(类型可以不同)。
应用:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto transformed = vec | views::transform([](int x){ return to_string(x); });
for (auto x : transformed)
cout << x << ' ';
作用:将容器中的所有元素转换成字符串,并打印出来。
如果单纯只输出,以上代码可写为:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : vec | views::transform([](int x){ return to_string(x); }))
cout << x << ' ';
结果:1 2 3 4 5 6 7 8 9
3.reverse
反转遍历顺序。
基本语法:
auto reversed = range | views::reverse;
reversed
为一个名为reversed
的视图对象。
应用:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : vec | views::reverse)
cout << x << ' ';
结果:9 8 7 6 5 4 3 2 1
作用:将容器逆序输出。
4. take / drop
截取或跳过元素。
基本语法:
auto first_n = range | views::take(n); // 前 n 个
auto skip_n = range | views::drop(n); // 跳过前 n 个
详细说明:
操作 | 行为 |
---|---|
take(n) | 最多取 n 个元素。如果不足 n 个,就取完为止。 |
drop(n) | 跳过前 n 个元素,返回剩余部分。若总数 ≤ n,则为空。 |
优点:不会越界,行为定义良好。
应用:
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : vec | views::take(5) | views::drop(2))
cout << x << ' ';
结果:3 4 5
作用:输出容器前五个元素并跳过前两个元素。
注意:views
的顺序不一样结果也不一样
vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : vec | views::drop(2) | views::take(5))
cout << x << ' ';
结果:3 4 5 6 7
5. join
扁平化嵌套结构。
基本语法:
auto flat = nested_range | std::views::join;
flat
为一个名为flat
的视图对象。- 要求内层也是一个
range
,即“范围的范围”(range<range<T>>
)。 - 可以将容器降低一个维度。
应用:
vector<vector<int>> vec{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (auto x : vec | views::join)
cout << x << ' ';
结果:1 2 3 4 5 6 7 8 9
作用:将二维 vector
输出成一维 vector
。
综合示例
vector<vector<int>> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
auto ans = vec | views::join // 扁平化为一维: 1 2 3 4 5 6 7 8 9 10 11 12
| views::drop(1) // 跳过第一个元素: 2 3 4 5 6 7 8 9 10 11 12
| views::take(5) // 取前5个: 2 3 4 5 6
| views::transform([](int n){ return n * n; }) // 转换为平方: 4 9 16 25 36
| views::filter([](int n){ return n % 2 == 0; }) // 只取偶数: 4 16 36
| views::reverse; // 反转: 36 16 4
for (int x : ans)
cout << x << ' ';
结果:36 16 4