**C++20 里程碑:使用 std::ranges 进行链式查询的完整指南**

在 C++20 之前,对容器的查询通常需要编写一系列标准算法,代码往往显得冗长且难以阅读。C++20 通过引入 std::ranges 与管道操作符(|)彻底改变了这一点。本文将演示如何利用 std::ranges 在单行代码中完成复杂的数据筛选、变换和排序,极大提升代码可读性与可维护性。


1. std::ranges 的基本概念

关键词 含义 示例
视图(View) 逻辑上对序列进行“投影”,不复制数据 std::views::filterstd::views::transform
管道操作符 把视图链连接成一条链 data | std::views::filter(...) | std::views::transform(...)
谓词/转换函数 传给视图的自定义函数 [](int x){ return x%2==0; }

提示:视图是延迟求值的,直到你实际遍历它们为止。


2. 经典示例:从一组整数中筛选偶数、取平方并排序

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

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

    auto processed = numbers
        | std::views::filter([](int n){ return n % 2 == 0; })          // 只保留偶数
        | std::views::transform([](int n){ return n * n; })           // 取平方
        | std::views::common();                                       // 转为可随机访问

    std::vector <int> sorted(processed.begin(), processed.end());
    std::ranges::sort(sorted);

    std::cout << "Result: ";
    for (int n : sorted)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出:

Result: 4 16 36 64 

说明

  • std::views::common() 用于将视图转换为支持随机访问的容器(std::vector)。
  • std::ranges::sort 只适用于随机访问容器;若你不需要排序,直接遍历视图即可。

3. 高级用法:结合多种视图与自定义谓词

假设我们要处理一个 std::vector<std::string>,需求是:

  1. 只保留长度大于 5 的字符串
  2. 转为大写
  3. 按字典序倒序排列
#include <iostream>
#include <vector>
#include <string>
#include <ranges>
#include <algorithm>
#include <cctype>

int main() {
    std::vector<std::string> words{"algorithm", "range", "view", "pipeline", "lambda", "function"};

    auto uppercase = [](std::string s) {
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    };

    auto processed = words
        | std::views::filter([](const std::string& s){ return s.size() > 5; })
        | std::views::transform(uppercase)
        | std::views::common();

    std::vector<std::string> sorted(processed.begin(), processed.end());
    std::ranges::sort(sorted, std::greater<>{});

    for (const auto& s : sorted)
        std::cout << s << ' ';
}

输出:

ALGORITHM FUNCTION 

4. 性能考量

  • 延迟执行:视图在迭代时才真正执行,避免了中间容器的复制。
  • 内存占用:只保留需要的元素,节省空间。
  • 可组合性:可以链式叠加视图,保持单一职责。

注意:若视图链包含 过滤变换,在每个元素上都会执行两次操作(一次过滤一次变换)。如果变换开销较大,可考虑先变换再过滤。


5. 与传统算法对比

需求 C++14 示例 C++20 std::ranges 示例
取偶数并平方 std::copy_if + std::transform views::filter + views::transform
复杂筛选 多个 std::copy_if 单行链式调用
可读性 代码行数多 代码简洁、直观

6. 结语

C++20 的 std::ranges 为我们提供了一套强大而优雅的数据处理工具,让传统算法变得更具表现力。熟练运用视图和管道操作符后,复杂的数据处理逻辑都可以被压缩成一行代码,既提升了可读性,也减少了潜在的错误。

在后续的项目中,建议你:

  1. 先从简单的 filtertransform 开始尝试。
  2. 熟悉 common()indirectly_readable 等概念,确保视图的类型兼容。
  3. 在性能敏感的地方,结合 std::views::take, std::views::drop, std::views::split 等高级视图进一步优化。

祝你编码愉快,玩转 C++20!

发表评论