0

0

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

P粉602998670

P粉602998670

发布时间:2025-08-12 13:05:01

|

484人浏览过

|

来源于php中文网

原创

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 
#include 
#include 
#include 

int main() {
    std::vector 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 
#include 
#include 
#include 

int main() {
    std::vector 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)
适配器只取第一个满足条件的元素,一旦找到,计算就会停止。这避免了对整个向量进行不必要的处理,从而提高了效率。

如何自定义范围适配器?

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

Haiper
Haiper

一个感知模型驱动的AI视频生成和重绘工具,提供文字转视频、图片动画化、视频重绘等功能

下载
#include 
#include 
#include 
#include 

namespace my_ranges {

    template 
    class repeat_view : public std::ranges::view_interface> {
    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 
    repeat_view(ViewableRange, int) -> repeat_view;

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

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

int main() {
    std::vector 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 
#include 
#include 
#include 
#include 

int main() {
    std::vector 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需要仔细考虑线程安全问题,避免出现数据竞争和死锁等问题。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

223

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

84

2025.10.17

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

471

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

387

2023.08.14

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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