在 C++20 中,std::ranges 库为我们提供了一套强大的工具,使得对容器、迭代器以及任意可迭代序列的操作变得更直观、更可组合。核心概念是 视图(view),它是对原始序列的“轻量级”包装,提供了惰性评估、无副作用的子集或变换功能。下面我们通过一个完整示例来演示如何利用 std::ranges::views 对整数序列进行过滤、映射、排序等操作,并与传统 STL 算法进行对比。
1. 基本视图操作
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector <int> nums = {9, 3, 5, 12, 7, 2, 8, 4};
// 1) 过滤出偶数
auto evens = nums | std::views::filter([](int x){ return x % 2 == 0; });
// 2) 对偶数进行平方
auto squares = evens | std::views::transform([](int x){ return x * x; });
// 3) 取前 3 个元素
auto first_three = squares | std::views::take(3);
std::cout << "Filtered, transformed, first 3 squares of evens:\n";
for (int n : first_three) {
std::cout << n << ' ';
}
std::cout << '\n';
}
输出:
Filtered, transformed, first 3 squares of evens:
4 16 64
解析
std::views::filter根据谓词过滤序列。std::views::transform对每个元素应用函数。std::views::take截取前 N 个元素。
这三个视图的组合实现了:偶数 → 平方 → 取前三 的完整链式操作,且整个过程是惰性求值,只有当真正迭代first_three时才会执行。
2. 视图与 std::ranges::sort
在 C++20 中,std::ranges::sort 可以直接作用于任何可随机访问的序列。若想对视图中的数据排序,需要先将其转换为容器,或者使用 std::ranges::to(C++23)等工具。下面演示在视图链的基础上先收集到一个容器再排序:
// 4) 先把前面得到的 squares 变成 vector
std::vector <int> squares_vec(first_three.begin(), first_three.end());
// 5) 对 squares_vec 进行降序排序
std::ranges::sort(squares_vec, std::greater<>());
std::cout << "Descending sorted squares:\n";
for (int n : squares_vec) {
std::cout << n << ' ';
}
std::cout << '\n';
输出:
Descending sorted squares:
64 16 4
这里我们利用
std::ranges::sort的简洁接口替代传统std::sort的写法,显得更直观。
3. 与传统 STL 的对比
传统 STL 实现上述逻辑(不使用视图)大约需要 15 行以上的代码,包括临时容器、循环、条件判断等。视图让代码更紧凑、可读性更好,并且因为惰性求值,避免了不必要的拷贝和临时对象。
小结
- 视图是对容器的“视图”,不占用额外空间。
- 操作链式、惰性求值、可组合。
- 与
std::ranges::sort、std::ranges::find等配合使用,能写出更简洁、可维护的 C++20 代码。
通过 std::ranges::views,你可以在 C++20 中以函数式编程风格轻松完成复杂的数据处理任务。尝试在你自己的项目中引入视图,感受代码风格与性能的双重提升。