**使用C++20的std::ranges对容器进行高级过滤**

在C++20中,标准库新增了std::ranges命名空间,它为容器操作提供了更直观、更强大的视图(view)与适配器(adapter)。通过组合这些适配器,开发者可以像使用函数式编程语言那样,对容器进行链式查询、过滤、变换等操作,而不需要显式地编写循环或中间变量。

下面以一个常见场景为例:在一个整数向量中,找出所有大于等于10且能被3整除的偶数,然后将它们的平方累加到结果中。

#include <iostream>
#include <vector>
#include <ranges>
#include <numeric>

int main() {
    std::vector <int> data{3, 12, 17, 24, 30, 41, 54, 66, 79, 90};

    // 1. 过滤:仅保留 >=10
    // 2. 过滤:能被3整除
    // 3. 过滤:偶数
    // 4. 变换:平方
    // 5. 归约:求和
    auto result = std::ranges::views::filter([](int x){ return x >= 10; })
                 | std::ranges::views::filter([](int x){ return x % 3 == 0; })
                 | std::ranges::views::filter([](int x){ return x % 2 == 0; })
                 | std::ranges::views::transform([](int x){ return x * x; })
                 | std::ranges::accumulate(0, std::plus<>());

    std::cout << "结果为: " << result << std::endl;
    return 0;
}

代码解析

  1. 视图(View)链式组合
    • std::ranges::views::filter 接受一个谓词,返回一个“延迟执行”的过滤视图。
    • std::ranges::views::transform 接受一个变换函数,返回一个“延迟执行”的变换视图。
    • 使用管道符 | 可以像 Unix shell 那样将视图链式组合,形成一个完整的查询管道。
  2. 延迟求值
    • 视图本身不存储数据,只是对底层容器进行“按需”访问。
    • 只有在执行 std::ranges::accumulate 时才会真正遍历一次容器。
  3. 高内聚的可读性
    • 读者可以像阅读自然语言一样,先看“过滤 >=10”,再看“过滤能被3整除”,再看“过滤偶数”,再看“平方”,最后求和。
    • 与传统的多重循环或中间临时容器相比,代码更简洁,维护成本更低。

进一步优化

如果查询条件较多,手动堆叠多层 filter 可能显得繁琐。C++20 还提供了 std::ranges::views::filter 的组合写法,或使用 std::ranges::views::filterpredicate 组合:

auto combined_predicate = [](int x){ return x >= 10; } &&
                          [](int x){ return x % 3 == 0; } &&
                          [](int x){ return x % 2 == 0; };

auto result = data | std::ranges::views::filter(combined_predicate)
                   | std::ranges::views::transform([](int x){ return x * x; })
                   | std::ranges::accumulate(0, std::plus<>());

常见坑点

场景 说明 解决方案
视图链中使用 `std::vector
data需要 const 访问 |views::filter默认返回auto,对原容器的引用为 const | 直接使用std::ranges::views::all(data),或将data声明为const`
结果期望为 `std::vector
|views::transform产生的是一个生成器,若需要实际容器,需to_vector()|data std::ranges::views::transform(… ) std::ranges::to()`

总结

C++20 的 std::ranges 让容器操作变得既简洁又高效。通过视图链式组合,开发者能够快速实现复杂的过滤、变换与聚合逻辑,而无需手写循环。掌握 std::ranges 的使用方式,既能提升代码可读性,也能在性能上获得一定的优势,特别是在需要多次遍历同一容器的场景中。

发表评论