在 C++20 之前,对容器的查询通常需要编写一系列标准算法,代码往往显得冗长且难以阅读。C++20 通过引入 std::ranges 与管道操作符(|)彻底改变了这一点。本文将演示如何利用 std::ranges 在单行代码中完成复杂的数据筛选、变换和排序,极大提升代码可读性与可维护性。
1. std::ranges 的基本概念
| 关键词 | 含义 | 示例 |
|---|---|---|
| 视图(View) | 逻辑上对序列进行“投影”,不复制数据 | std::views::filter、std::views::transform |
| 管道操作符 | 把视图链连接成一条链 | data | std::views::filter(...) | std::views::transform(...) |
| 谓词/转换函数 | 传给视图的自定义函数 | [](int x){ return x%2==0; } |
提示:视图是延迟求值的,直到你实际遍历它们为止。
2. 经典示例:从一组整数中筛选偶数、取平方并排序
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector <int> numbers{1, 4, 3, 6, 8, 7, 2};
auto processed = numbers
| std::views::filter([](int n){ return n % 2 == 0; }) // 只保留偶数
| std::views::transform([](int n){ return n * n; }) // 取平方
| std::views::common(); // 转为可随机访问
std::vector <int> sorted(processed.begin(), processed.end());
std::ranges::sort(sorted);
std::cout << "Result: ";
for (int n : sorted)
std::cout << n << ' ';
std::cout << '\n';
}
输出:
Result: 4 16 36 64
说明
std::views::common()用于将视图转换为支持随机访问的容器(std::vector)。std::ranges::sort只适用于随机访问容器;若你不需要排序,直接遍历视图即可。
3. 高级用法:结合多种视图与自定义谓词
假设我们要处理一个 std::vector<std::string>,需求是:
- 只保留长度大于 5 的字符串
- 转为大写
- 按字典序倒序排列
#include <iostream>
#include <vector>
#include <string>
#include <ranges>
#include <algorithm>
#include <cctype>
int main() {
std::vector<std::string> words{"algorithm", "range", "view", "pipeline", "lambda", "function"};
auto uppercase = [](std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
return s;
};
auto processed = words
| std::views::filter([](const std::string& s){ return s.size() > 5; })
| std::views::transform(uppercase)
| std::views::common();
std::vector<std::string> sorted(processed.begin(), processed.end());
std::ranges::sort(sorted, std::greater<>{});
for (const auto& s : sorted)
std::cout << s << ' ';
}
输出:
ALGORITHM FUNCTION
4. 性能考量
- 延迟执行:视图在迭代时才真正执行,避免了中间容器的复制。
- 内存占用:只保留需要的元素,节省空间。
- 可组合性:可以链式叠加视图,保持单一职责。
注意:若视图链包含 过滤 与 变换,在每个元素上都会执行两次操作(一次过滤一次变换)。如果变换开销较大,可考虑先变换再过滤。
5. 与传统算法对比
| 需求 | C++14 示例 | C++20 std::ranges 示例 |
|---|---|---|
| 取偶数并平方 | std::copy_if + std::transform |
views::filter + views::transform |
| 复杂筛选 | 多个 std::copy_if |
单行链式调用 |
| 可读性 | 代码行数多 | 代码简洁、直观 |
6. 结语
C++20 的 std::ranges 为我们提供了一套强大而优雅的数据处理工具,让传统算法变得更具表现力。熟练运用视图和管道操作符后,复杂的数据处理逻辑都可以被压缩成一行代码,既提升了可读性,也减少了潜在的错误。
在后续的项目中,建议你:
- 先从简单的
filter与transform开始尝试。 - 熟悉
common()、indirectly_readable等概念,确保视图的类型兼容。 - 在性能敏感的地方,结合
std::views::take,std::views::drop,std::views::split等高级视图进一步优化。
祝你编码愉快,玩转 C++20!