C++系列十:日常学习-范围库Ranges
前言
不错麽
内容参考
总结注意点:
- 确保你的C++编译器支持C++20标准
- 包含 ranges 头文件
- views的操作是惰性的,它们不会立即执行,而是在需要时计算。这意味着你可以构建复杂的管道,而不必担心性能问题。提供性能优势,因为它们避免了不必要的数据拷贝和临时存储。在处理大型数据集时,这种优化尤为重要。
- 使用views不会修改原始数据,它们只是提供了对数据的查看和操作方式。因此,原始数据保持不变,不会被修改。
- 要小心处理可能的异常情况,例如范围越界或无效的操作。可以使用try-catch块来处理异常。
- 管道操作符 |(竖线符号)=>数据处理操作可以从左到右依次执行,
介绍
C++20引入了Ranges库,其中的views
是该库的一个关键组成部分。views
提供了一种现代化的、功能强大的方法来处理数据序列,它基于"range-based"编程范式,允许你以声明性的方式对数据序列进行操作,而无需手动编写循环。以下是关于views
的详细介绍:
-
什么是
views
?views
是C++20中Ranges库的一部分,它代表了一个数据序列的虚拟视图。这个视图允许你以一种便捷和现代的方式访问和操作数据,同时不需要实际地拷贝或修改原始数据。views
的操作是惰性的,只有在需要的时候才会执行。 -
视图的创建:
你可以通过调用标准容器的
views
成员函数或使用适配器来创建视图。例如,可以使用std::vector
创建一个视图:std::vector<int> numbers = {1, 2, 3, 4, 5}; auto view = numbers | std::views::transform([](int x) { return x * 2; });
在这里,
std::views::transform
是一个视图适配器,它将一个函数应用于容器中的每个元素,创建一个新的视图。 -
视图的操作:
一旦创建了视图,你可以对其执行各种操作,这些操作包括但不限于:
-
筛选(filtering):筛选出满足特定条件的元素。
-
映射(mapping):将函数应用于序列中的每个元素。
-
切片(slicing):选择范围内的元素。
-
排序(sorting):对元素进行排序。
你可以将多个操作组合在一起来创建复杂的数据处理管道,而这些操作都是惰性执行的。
-
-
遍历视图:
一旦创建了视图,你可以使用
for
循环或范围for
循环来遍历它。视图会在遍历时动态计算元素,而不会一次性生成所有元素。for (int num : view) { std::cout << num << " "; }
-
性能优势:
views
具有优化的性能。它们避免了不必要的数据拷贝和临时存储,使得在处理大型数据集时非常高效。 -
自定义视图:
你还可以创建自定义的视图,通过实现必要的迭代器和操作符来定义你自己的数据序列操作。
-
views
的应用场景:views
适用于各种应用场景,包括数据转换、筛选、数据流处理、映射、集合操作等。它们可以使你的代码更加清晰、可读和高效。
总之,views
是C++20引入的一个重要特性,它使得序列处理变得更加简单和现代化。它们提供了一种优雅的方式来处理数据序列,避免了繁琐的手动迭代和数据操作。在使用时,请确保你的编译器支持C++20标准并了解如何正确使用Ranges库以发挥其强大的功能。
举例:
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用views::transform将每个元素翻倍=>2 4 6 8 10
auto doubled = numbers | std::views::transform([](int x) { return x * 2; });
// 使用views::filter筛选偶数 =>2 4
auto evenNumbers = numbers | std::views::filter([](int x) { return x % 2 == 0; });
// 使用views::slice选择范围[1, 3)=> 2 3 4
auto slicedRange = numbers | std::views::slice(1, 4);
// 链式操作:筛选偶数,然后翻倍=>4 8
auto result = numbers | std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * 2; });
// 使用views::iota生成范围[1, 10)=>1~9
auto sequence = std::views::iota(1, 10);
// 生成无限递增序列~~~
auto infiniteSequence = std::views::iota(1);
// 使用views::reverse反向迭代容器=>5 4 3 2 1
auto reversed = numbers | std::views::reverse;
// 使用views::concat合并两个容器
std::vector<int> numbers1 = {1, 2, 3};
std::vector<int> numbers2 = {4, 5, 6};
auto combined = std::views::concat(numbers1, numbers2);
for (int num : doubled) {
std::cout << num << " ";
//拆分字符串
std::string text = "Hello,World,C++,Ranges";
auto splitView = text | std::views::split(',');
for (const auto& range : splitView) {
std::string token(range.begin(), range.end());
std::cout << token << std::endl;
}
//对比:
auto const ints = {0,1,2,3,4,5};
auto even = [](int i) { return 0 == i % 2; };
auto square = [](int i) { return i * i; };
// 组合视图的“管道”语法:
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}
std::cout << '\n';
// 传统的“函数式”组合语法:
for (int i : std::views::transform(std::views::filter(ints, even), square)) {
std::cout << i << ' ';
}
还有许多适配器就不一一举例说明了。
高深的就不探究了,会使用好工具就得了。