首页 > 后端开发 > C++ > 正文

如何应用C++20的range特性 范围适配器与惰性求值实现

P粉602998670
发布: 2025-08-12 13:05:01
原创
476人浏览过

c++++20的range特性提供了一种更现代、便捷的操作序列数据的方式,其核心在于range概念与适配器的结合,支持惰性求值,提升效率。1. range是可迭代的对象,适配器用于转换和过滤range,操作通常为惰性求值;2. 使用std::views可以以声明式方式处理数据,如filter筛选偶数,transform进行平方转换;3. 惰性求值仅在需要结果时计算,避免不必要的处理,显著提升性能;4. 可自定义范围适配器,如创建repeat_view实现元素重复逻辑;5. ranges相较传统迭代器更为抽象简洁,隐藏底层复杂性并支持组合多个适配器形成流水线;6. 引入ranges可逐步进行,从简单用例开始迁移,并注意惰性求值触发及兼容性问题;7. 在并发编程中,ranges可用于分割数据范围并行处理,提高效率,但需考虑线程安全。

如何应用C++20的range特性 范围适配器与惰性求值实现

C++20的range特性,简单来说,就是一种更现代、更便捷的方式来操作序列数据,它结合了范围适配器和惰性求值,让我们能够以一种声明式、函数式的方式处理数据,代码更简洁,效率也更高。

如何应用C++20的range特性 范围适配器与惰性求值实现

范围适配器与惰性求值实现

C++20 Ranges的核心在于

range
登录后复制
的概念和与之配套的适配器。
range
登录后复制
是一个可以像容器一样迭代的对象,而适配器则可以对
range
登录后复制
进行转换和过滤,而且这些转换和过滤操作通常是惰性求值的,只有在真正需要结果时才会进行计算。

立即学习C++免费学习笔记(深入)”;

如何应用C++20的range特性 范围适配器与惰性求值实现

如何使用
std::views
登录后复制
进行数据转换和过滤?

std::views
登录后复制
是C++20 Ranges库中一组强大的适配器,它允许我们以一种简洁而高效的方式转换和过滤数据。例如,假设我们有一个整数向量,我们想筛选出其中的偶数,并将它们平方。使用
std::views
登录后复制
,我们可以这样做:

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

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

    auto even_squared = numbers | std::views::filter([](int n){ return n % 2 == 0; })
                                 | std::views::transform([](int n){ return n * n; });

    for (int num : even_squared) {
        std::cout << num << " "; // 输出:4 16 36 64 100
    }
    std::cout << std::endl;

    return 0;
}
登录后复制

这里,

|
登录后复制
运算符将
numbers
登录后复制
向量传递给
std::views::filter
登录后复制
适配器,该适配器只保留偶数。然后,结果被传递给
std::views::transform
登录后复制
适配器,该适配器将每个偶数平方。整个过程是惰性求值的,只有在循环遍历
even_squared
登录后复制
时,才会真正执行过滤和转换操作。

如何应用C++20的range特性 范围适配器与惰性求值实现

惰性求值如何提升性能?

惰性求值是Ranges库的一个关键特性,它可以显著提升性能,尤其是在处理大型数据集时。考虑以下场景:我们需要从一个包含数百万个元素的向量中找到第一个大于100的偶数。如果没有惰性求值,我们需要遍历整个向量,筛选出所有偶数,然后再找到第一个大于100的数。但是,使用Ranges和惰性求值,我们可以在找到第一个满足条件的元素后立即停止计算。

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

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 102, 104, 106}; // 假设向量很大

    auto first_even_greater_than_100 = numbers | std::views::filter([](int n){ return n % 2 == 0; })
                                                  | std::views::filter([](int n){ return n > 100; })
                                                  | std::views::take(1);

    for (int num : first_even_greater_than_100) {
        std::cout << num << std::endl; // 输出:102
        break; // 找到第一个就停止
    }

    return 0;
}
登录后复制

在这个例子中,

std::views::take(1)
登录后复制
适配器只取第一个满足条件的元素,一旦找到,计算就会停止。这避免了对整个向量进行不必要的处理,从而提高了效率。

如何自定义范围适配器?

除了使用标准库提供的适配器,我们还可以自定义范围适配器,以满足特定的需求。例如,我们可以创建一个适配器,将一个范围中的每个元素重复指定的次数。

英特尔AI工具
英特尔AI工具

英特尔AI与机器学习解决方案

英特尔AI工具 70
查看详情 英特尔AI工具
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

namespace my_ranges {

    template <typename ViewableRange>
    class repeat_view : public std::ranges::view_interface<repeat_view<ViewableRange>> {
    private:
        ViewableRange base_;
        int count_;

    public:
        repeat_view(ViewableRange base, int count) : base_(std::move(base)), count_(count) {}

        auto begin() {
            return std::ranges::begin(base_); // 简化起见,这里只返回基础范围的begin
        }

        auto end() {
            return std::ranges::end(base_); // 简化起见,这里只返回基础范围的end
        }
    };

    template <typename ViewableRange>
    repeat_view(ViewableRange, int) -> repeat_view<ViewableRange>;

    inline namespace customization_point {
        struct repeat_fn {
            template <typename ViewableRange>
            constexpr auto operator()(ViewableRange&& viewable_range, int count) const {
                return repeat_view(std::forward<ViewableRange>(viewable_range), count);
            }
        };

        inline constexpr repeat_fn repeat;
    } // namespace customization_point
} // namespace my_ranges

int main() {
    std::vector<int> numbers = {1, 2, 3};

    auto repeated_numbers = numbers | my_ranges::repeat(2);

    // 这里需要更完整的迭代器实现才能正确输出,此处仅为演示概念
    // 实际使用需要完善repeat_view的迭代器逻辑

    return 0;
}
登录后复制

这个例子只是一个简化的演示,实际的

repeat_view
登录后复制
需要更复杂的迭代器实现来正确处理元素的重复。但是,它展示了如何自定义范围适配器的基本思路。

Ranges与传统迭代器的区别与优势?

Ranges提供了一种更高级别的抽象,隐藏了底层迭代器的复杂性。传统的迭代器需要手动管理迭代器的递增和解引用,而Ranges允许我们以一种更声明式的方式操作数据,例如使用

std::views::filter
登录后复制
std::views::transform
登录后复制
来过滤和转换数据,而无需关心底层的迭代器细节。

此外,Ranges还支持组合,我们可以将多个适配器组合在一起,形成复杂的数据处理流水线。这种组合性使得代码更简洁、更易于理解和维护。而使用传统迭代器实现相同的功能通常需要编写大量的循环和条件判断,代码会变得冗长而难以阅读。

如何在现有代码中逐步引入Ranges?

将Ranges引入现有代码库可以是一个逐步的过程。首先,可以从一些简单的用例开始,例如使用

std::views::filter
登录后复制
std::views::transform
登录后复制
来替代手动编写的循环和条件判断。然后,可以逐渐地将更多的代码迁移到Ranges,并自定义适配器来满足特定的需求。

在迁移过程中,需要注意Ranges的惰性求值特性。由于Ranges的操作是惰性求值的,因此在某些情况下,可能需要显式地触发计算,例如使用

std::ranges::to
登录后复制
将结果转换为容器。

此外,还需要注意Ranges的兼容性。C++20 Ranges库是C++20标准的一部分,因此需要使用支持C++20的编译器才能使用Ranges。如果代码库需要兼容旧版本的编译器,可以考虑使用Ranges的polyfill库,例如range-v3。

Ranges在并发编程中的应用?

Ranges的惰性求值特性使其在并发编程中具有很大的潜力。我们可以将一个大型数据集分割成多个子范围,然后使用不同的线程并行处理这些子范围。由于Ranges的操作是惰性求值的,因此我们可以避免在分割数据时进行不必要的拷贝,从而提高效率。

例如,我们可以使用

std::views::chunk
登录后复制
将一个范围分割成多个大小相等的子范围,然后使用
std::for_each
登录后复制
算法并行处理这些子范围。

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

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

    auto chunks = numbers | std::views::chunk(3);

    std::for_each(std::execution::par, std::ranges::begin(chunks), std::ranges::end(chunks), [](auto chunk){
        // 在不同的线程中处理每个子范围
        for (int num : chunk) {
            std::cout << num << " ";
        }
        std::cout << std::endl;
    });

    return 0;
}
登录后复制

这个例子展示了如何使用Ranges和

std::for_each
登录后复制
算法并行处理数据。需要注意的是,在并发编程中使用Ranges需要仔细考虑线程安全问题,避免出现数据竞争和死锁等问题。

以上就是如何应用C++20的range特性 范围适配器与惰性求值实现的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号