**如何在 C++20 中使用 std::ranges 进行高效数据过滤**

在 C++20 中,std::ranges 库为容器提供了一种更声明式、更表达式化的操作方式。相比传统的迭代器 + std::copy_ifstd::remove_ifstd::ranges 通过管道化操作实现了更简洁且易读的代码。本文将从基础语法、常用视图(view)以及性能考量四个方面,介绍如何在实际项目中利用 std::ranges 进行数据过滤。


1. 基础语法与示例

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

int main() {
    std::vector <int> data{1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto even_numbers = data | std::ranges::views::filter([](int n){ return n % 2 == 0; });

    for (int n : even_numbers) {
        std::cout << n << ' ';
    }
    // 输出: 2 4 6 8
}
  • 管道符 |:将容器 data 连接到 filter 视图,形成一个新的可迭代范围。
  • views::filter:接收一个谓词(lambda 或函数),返回一个延迟评估的过滤视图。
  • 迭代器不必手动维护,只需按需遍历。

2. 常用视图(views)组合

std::ranges::views 提供了大量组合视图,常见的有:

视图 功能 示例
views::filter 过滤元素 view | views::filter(p)
views::transform 转换元素 view | views::transform(f)
views::take 取前 N 个 view | views::take(5)
views::drop 跳过前 N 个 view | views::drop(3)
views::reverse 反转顺序 view | views::reverse
views::stride 每隔 N 个 view | views::stride(2)
views::join 合并嵌套容器 view_of_views | views::join

组合示例:取前 5 个偶数并平方

auto result = data
             | std::ranges::views::filter([](int n){ return n % 2 == 0; })
             | std::ranges::views::take(5)
             | std::ranges::views::transform([](int n){ return n * n; });

for (int x : result) std::cout << x << ' ';  // 输出: 4 16 36 64 100

3. 与 STL 算法兼容

std::ranges 视图可以直接与标准算法一起使用,且能享受视图的延迟求值特性。

auto sum = std::accumulate(
    data | std::ranges::views::filter([](int n){ return n > 5; }),
    0
);

注意:某些算法(如 std::sort)需要可修改的范围,需使用 std::ranges::subrangestd::ranges::iota_view 等。


4. 性能考量

  1. 延迟求值
    视图在迭代时按需执行过滤/转换,避免一次性生成临时容器,降低内存占用。

  2. 小对象
    视图是“轻量级”对象,通常只包含迭代器或函数对象,复制开销极小。

  3. 缓存友好
    由于不产生新容器,缓存命中率更高。
    但若视图链很长,可能会导致多层函数调用;可使用 std::ranges::views::common 将范围转为常规迭代器以减少层级。

  4. 并行执行
    C++20 为 std::ranges::views 加入了 std::execution 支持,可通过 std::ranges::copy 等函数并行化:

    std::vector <int> out(data.size());
    std::ranges::copy(
        data | std::ranges::views::filter([](int n){ return n % 2 == 0; }),
        std::execution::par, std::begin(out)
    );

5. 典型应用场景

  • 日志过滤
    在高频日志系统中,仅保留指定级别的日志条目,避免存储与 I/O 负载。

  • 网络包处理
    对入站数据包进行速率限制、内容检查等。

  • 大数据预处理
    对 CSV、JSON 等文件中大量行进行筛选与转换后,再交给机器学习模块。


6. 小结

  • std::ranges 提供了声明式链式的数据操作方式。
  • 通过 views::filterviews::transform 等组合,可实现复杂的数据流,代码简洁且易维护。
  • 延迟求值与轻量级对象使其在性能上优于传统迭代器+算法的做法。
  • 结合并行执行,可进一步提升吞吐量。

建议在新项目中使用 C++20 的 std::ranges 进行数据过滤与转换,以提升代码质量与运行效率。祝你编码愉快!

发表评论