如何使用 C++20 std::ranges 与 std::views 进行惰性管道式数据处理?

在 C++20 中, 头文件引入了一套强大的管道式、惰性求值的数据操作工具。相比传统的迭代器写法,它提供了更简洁的语法,更直观的链式组合,以及显著的可读性提升。下面通过一个完整的示例,演示如何利用 std::ranges::views 对一个整数序列进行筛选、变换、排序、去重,并最终将结果写入容器。

1. 准备数据

#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>

int main() {
    std::vector <int> data{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

2. 定义操作链

    auto processed = data
        | std::ranges::views::filter([](int n){ return n % 2 == 0; })          // 取偶数
        | std::ranges::views::transform([](int n){ return n * n; })            // 平方
        | std::ranges::views::filter([](int n){ return n > 50; })             // 大于50
        | std::ranges::views::unique();                                       // 去重

注意unique 是一个 view,它在调用 std::ranges::to 或者通过 std::ranges::for_each 之类的终结操作时才会触发真正的去重工作。

3. 终结操作:复制到容器

    std::vector <int> result;
    std::ranges::to(result)(processed);  // C++23 提供的简化语法

如果使用 C++20,终结操作可以写成 std::copy(processed.begin(), processed.end(), std::back_inserter(result));

4. 输出结果

    std::cout << "处理结果: ";
    for (int x : result) std::cout << x << ' ';
    std::cout << '\n';
}

5. 运行效果

$ ./ranges_demo
处理结果: 64 100 144 196 256 324 400 
  • 解释:原始序列 [1..15] 先筛选偶数得到 [2,4,6,8,10,12,14];平方后 [4,16,36,64,100,144,196];再筛选大于 50 的得到 [64,100,144,196];最后去重(此处无重复)得到最终结果。

6. 进一步优化与技巧

  1. 组合视图:使用 std::ranges::views::all 可以包装任何可遍历对象,保持兼容性。
  2. 链式管道:由于视图是惰性求值,整个链式操作在真正需要数据时才执行,避免不必要的拷贝。
  3. 自定义视图:通过 std::ranges::view_facade 可以轻松创建自己的视图,例如滑动窗口、分组等。
  4. 性能考虑:在极大数据量下,避免在视图链中出现昂贵的临时对象;若需多次遍历,考虑先复制为容器。

7. 小结

C++20 的 `

` 与 “ 为现代 C++ 提供了一种声明式、惰性、链式的数据处理方式,既提升了代码可读性,又保持了高性能。熟练掌握视图组合,将使你的数据操作代码更简洁、更易维护。

发表评论