在 C++20 中,标准库新增了一个强大的特性:范围(Ranges)库。它把 STL 容器、迭代器、算法等概念整合到了一套统一的接口中,使代码更简洁、表达更自然。下面通过几个实例来演示如何使用 Range,掌握其核心概念和常见工具。
1. 范围(Ranges)基础概念
- View(视图):对原始序列的“轻量级”视图,支持链式操作,避免了中间临时容器。典型例子:
std::views::filter、std::views::transform、std::views::reverse等。 - View 适配器:将原始序列转换为视图的函数,例如
std::views::all把任何可迭代对象转换为可迭代视图。 - Pipe 操作符(|):实现链式调用。
range | view1 | view2 | view3依次把视图应用到range上。
2. 简单使用示例
2.1 过滤偶数
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector <int> nums = {1,2,3,4,5,6,7,8,9,10};
auto evens = nums | std::views::filter([](int n){ return n % 2 == 0; });
for (int n : evens)
std::cout << n << ' '; // 输出:2 4 6 8 10
}
2.2 变换为平方
auto squares = nums | std::views::transform([](int n){ return n * n; });
for (int n : squares)
std::cout << n << ' '; // 输出:1 4 9 16 25 ...
2.3 组合使用
auto even_squares = nums
| std::views::filter([](int n){ return n % 2 == 0; })
| std::views::transform([](int n){ return n * n; });
for (int n : even_squares)
std::cout << n << ' '; // 输出:4 16 36 64 100
3. 逆序视图与反转
auto rev = nums | std::views::reverse;
for (int n : rev)
std::cout << n << ' '; // 输出:10 9 8 7 6 5 4 3 2 1
注意:reverse 并不创建新容器,而是仅通过逆向迭代器遍历。
4. std::ranges::for_each 与 std::ranges::copy
4.1 for_each
std::ranges::for_each(even_squares, [](int n){ std::cout << n << '\n'; });
4.2 copy 到输出流
std::ranges::copy(even_squares, std::ostream_iterator <int>{std::cout, " "});
// 输出:4 16 36 64 100
5. 自定义视图适配器
假设我们想实现一个 take 视图,截取前 N 个元素。
template<std::ranges::input_range R>
auto take_view(R&& r, std::size_t n)
{
struct view {
R range;
std::size_t count;
auto begin() { return std::ranges::begin(range); }
auto end() {
auto it = std::ranges::begin(range);
std::advance(it, std::min(count, std::ranges::size(range)));
return it;
}
};
return view{ std::forward <R>(r), n };
}
int main() {
std::vector <int> data{1,2,3,4,5};
for (int x : take_view(data, 3))
std::cout << x << ' '; // 输出:1 2 3
}
提示:在 C++20 里实现完整的自定义视图需要遵循
std::ranges::view_interface并实现begin()、end()、size()等成员;上例简化实现,适用于教学演示。
6. 常见视图适配器汇总
| 视图名称 | 作用 |
|---|---|
std::views::all |
将任何可迭代对象转为视图 |
std::views::filter |
过滤元素 |
std::views::transform |
映射元素 |
std::views::reverse |
逆序 |
std::views::drop |
跳过前 N 个元素 |
std::views::take |
取前 N 个元素 |
std::views::join |
连接嵌套容器 |
std::views::stride |
取每 K 个元素 |
std::views::common |
让视图支持 size() 与 empty() |
7. 性能与注意事项
- 延迟求值:视图是惰性求值的,只有在遍历时才计算,避免不必要的拷贝。
- 生命周期:视图内部存储对原始容器的引用,使用时请确保原始容器的生命周期至少与视图相同。
- 兼容性:Range 库在 C++20 中已正式标准化,支持主流编译器(gcc≥10, clang≥11, MSVC≥19.30)。
8. 小结
C++20 的 Range 库让算法与容器的组合变得更像函数式编程。通过 views::filter、views::transform、views::reverse 等视图适配器,代码更短、易读、可组合。掌握它们后,你可以在日常项目中写出更清晰、更高效的迭代逻辑。
练习建议:在项目中替换一段旧式
for循环,使用 Range 重写。观察性能与可维护性的差异,进一步体会 Range 的强大。