**如何使用 C++20 Ranges 与 Views 实现更简洁的数据处理**

在 C++20 中,std::ranges 库为我们提供了一套强大的工具,使得对容器、迭代器以及任意可迭代序列的操作变得更直观、更可组合。核心概念是 视图(view),它是对原始序列的“轻量级”包装,提供了惰性评估、无副作用的子集或变换功能。下面我们通过一个完整示例来演示如何利用 std::ranges::views 对整数序列进行过滤、映射、排序等操作,并与传统 STL 算法进行对比。

1. 基本视图操作

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

int main() {
    std::vector <int> nums = {9, 3, 5, 12, 7, 2, 8, 4};

    // 1) 过滤出偶数
    auto evens = nums | std::views::filter([](int x){ return x % 2 == 0; });

    // 2) 对偶数进行平方
    auto squares = evens | std::views::transform([](int x){ return x * x; });

    // 3) 取前 3 个元素
    auto first_three = squares | std::views::take(3);

    std::cout << "Filtered, transformed, first 3 squares of evens:\n";
    for (int n : first_three) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出:

Filtered, transformed, first 3 squares of evens:
4 16 64

解析

  • std::views::filter 根据谓词过滤序列。
  • std::views::transform 对每个元素应用函数。
  • std::views::take 截取前 N 个元素。
    这三个视图的组合实现了:偶数 → 平方 → 取前三 的完整链式操作,且整个过程是惰性求值,只有当真正迭代 first_three 时才会执行。

2. 视图与 std::ranges::sort

在 C++20 中,std::ranges::sort 可以直接作用于任何可随机访问的序列。若想对视图中的数据排序,需要先将其转换为容器,或者使用 std::ranges::to(C++23)等工具。下面演示在视图链的基础上先收集到一个容器再排序:

    // 4) 先把前面得到的 squares 变成 vector
    std::vector <int> squares_vec(first_three.begin(), first_three.end());

    // 5) 对 squares_vec 进行降序排序
    std::ranges::sort(squares_vec, std::greater<>());

    std::cout << "Descending sorted squares:\n";
    for (int n : squares_vec) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

输出:

Descending sorted squares:
64 16 4

这里我们利用 std::ranges::sort 的简洁接口替代传统 std::sort 的写法,显得更直观。

3. 与传统 STL 的对比

传统 STL 实现上述逻辑(不使用视图)大约需要 15 行以上的代码,包括临时容器、循环、条件判断等。视图让代码更紧凑、可读性更好,并且因为惰性求值,避免了不必要的拷贝和临时对象。

小结

  • 视图是对容器的“视图”,不占用额外空间。
  • 操作链式、惰性求值、可组合。
  • std::ranges::sortstd::ranges::find 等配合使用,能写出更简洁、可维护的 C++20 代码。

通过 std::ranges::views,你可以在 C++20 中以函数式编程风格轻松完成复杂的数据处理任务。尝试在你自己的项目中引入视图,感受代码风格与性能的双重提升。

发表评论