当前位置: 首页 > news >正文

C++23 views::zip 和 views::zip_transform (P2321R2) 深入解析

文章目录

    • 一、引言
    • 二、C++23与Ranges库背景知识
      • 2.1 C++23概述
      • 2.2 Ranges库回顾
    • 三、`views::zip` 详解
      • 3.1 功能与定义
      • 3.2 使用场景
      • 3.3 示例代码
    • 四、`views::zip_transform` 详解
      • 4.1 功能与定义
      • 4.2 使用场景
      • 4.3 示例代码
    • 五、`views::zip` 与 `views::zip_transform` 的对比
      • 5.1 功能差异
      • 5.2 使用场景差异
      • 5.3 代码复杂度差异
    • 六、总结

一、引言

在C++的发展历程中,每一个新版本都会带来一系列令人期待的新特性,这些特性不仅提升了语言的性能和表达能力,还为开发者提供了更加便捷和高效的编程方式。C++23作为C++标准的一个重要版本,引入了许多实用的特性,其中 views::zipviews::zip_transform (提案编号P2321R2)就是两个非常有价值的特性,它们与C++20引入的Ranges库紧密相关,为处理范围数据提供了新的视角和方法。

二、C++23与Ranges库背景知识

2.1 C++23概述

C++23是C++标准的下一个重要更新版本,虽然不如C++20那样具有颠覆性,但它依然带来了许多值得开发者关注的改进和新增特性。C++23在C++20的基础上进行了补充和优化,解决了一些细节问题,并引入了新的编程工具和方法,旨在进一步提升C++语言的功能和开发效率。

2.2 Ranges库回顾

C++20引入的Ranges库是一个重要特性,它彻底改变了我们处理序列数据的方式,提供了更富有表现力、更易组合的抽象。简单来说,Range就是一种可以遍历的序列,你可以把它想象成更智能、更灵活的数组或者容器。C++20引入了Ranges这个概念,让我们可以更方便地操作这些序列,例如,可以使用Ranges来过滤、转换、拼接序列等。

std::views 是C++20里提供的一系列工具函数,用来对序列进行各种变换。它可以帮助我们以一种非常直观的方式对序列进行操作,比如过滤、转换、切片等等。以下是一个简单的示例,展示了如何使用 std::views 来过滤出数组中的偶数,并将这些偶数加倍:

#include <iostream>
#include <vector>
#include <ranges>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; })| std::views::transform([](int n) { return n * 2; });for (int n : result) {std::cout << n << ' ';}return 0;
}

在这个示例中,我们使用 std::views::filterstd::views::transform 对序列进行了处理,代码不仅简洁,而且非常直观。

三、views::zip 详解

3.1 功能与定义

std::ranges::views::zip 是C++23引入的一个范围适配器,它接受一个或多个 view ,并生成一个 view ,其第 i 个元素是由所有视图的第 i 个元素组成的类似元组的值。生成的视图的大小是所有适配的视图大小的最小值。

在标头 <ranges> 中定义如下:

template < ranges::input_range ... Views >
requires ( ranges::view < Views> && ...) && ( sizeof...(Views) > 0 )
class zip_view
: public ranges::view_interface <zip_view< Views...>>
(1) (C++23)namespace views {
inline constexpr /*unspecified*/ zip = /*unspecified*/;
}
(2) (自 C++23)调用签名
template < ranges::viewable_range... Rs >
requires /* 见下文 */
constexpr ranges::view auto zip( Rs&&... rs ) ;
(自 C++23)

zip_view 始终实现 input_range ,并且若所有适配的 view 类型均实现 forward_rangebidirectional_rangerandom_access_rangesized_range 时实现对应的概念。

3.2 使用场景

views::zip 适用于需要同时遍历多个范围的场景,例如,当你需要对多个数组或容器进行并行处理时,可以使用 views::zip 将它们组合在一起,然后进行统一的操作。

3.3 示例代码

#include <list>
#include <array>
#include <tuple>
#include <ranges>
#include <vector>
#include <string>
#include <iostream>void print(auto const rem, auto const& range)
{for (std::cout << rem; auto const& elem : range)std::cout << elem << ' ';std::cout << '\n';
}int main()
{auto x = std::vector{1, 2, 3, 4};auto y = std::list<std::string>{"α", "β", "γ", "δ", "ε"};auto z = std::array{'A', 'B', 'C', 'D', 'E', 'F'};print("Source views:", "");print("x: ", x);print("y: ", y);print("z: ", z);print("\nzip(x,y,z):", "");for (std::tuple<int&, std::string&, char&> elem : std::views::zip(x, y, z)){std::cout << std::get<0>(elem) << ' '<< std::get<1>(elem) << ' '<< std::get<2>(elem) << '\n';std::get<char&>(elem) += ('a' - 'A'); // modifies the element of z}print("\nAfter modification, z: ", z);
}

其运行的结果是:

Source views:
x: 1 2 3 4
y: α β γ δ ε
z: A B C D E Fzip(x,y,z):
1 α A
2 β B
3 γ C
4 δ DAfter modification, z: a b c d E F

四、views::zip_transform 详解

4.1 功能与定义

std::ranges::views::zip_transform 同样是C++23引入的一个范围适配器,它接受一个可调用对象和一个或多个 view ,并生成一个 view ,其第 i 个元素是将可调用对象应用于所有视图的第 i 个元素的结果。

在标头 <ranges> 中定义如下:

template< std::copy_constructible F, ranges::input_range... Views >
requires (ranges::view<Views> && ...) && (sizeof...(Views) > 0) &&std::is_object_v<F> && std::regular_invocable<F&, ranges::range_reference_t<Views>...> &&/*can-reference*/<std::invoke_result_t<F&, ranges::range_reference_t<Views>...>>
class zip_transform_view: public ranges::view_interface<zip_transform_view<F, Views...>>
(1) (since C++23)namespace views {inline constexpr /*unspecified*/ zip_transform = /*unspecified*/;
}
(2) (since C++23)Call signature
template< class F, ranges::viewable_range... Rs >
requires /* see below */
constexpr auto zip_transform( F&& f, Rs&&... rs );
(since C++23)

4.2 使用场景

views::zip_transform 适用于需要对多个范围的元素进行某种计算或转换的场景,例如,你可以使用它来计算两个数组对应元素的和、差、积等。

4.3 示例代码

#include <iostream>
#include <vector>
#include <ranges>int main() {std::vector<int> a = {1, 2, 3, 4};std::vector<int> b = {5, 6, 7, 8};auto result = std::views::zip_transform([](int x, int y) { return x + y; }, a, b);for (int val : result) {std::cout << val << ' ';}std::cout << '\n';return 0;
}

在这个示例中,我们使用 views::zip_transform 计算了两个向量对应元素的和,并将结果输出。

五、views::zipviews::zip_transform 的对比

5.1 功能差异

  • views::zip 主要用于将多个范围的元素组合成元组,方便同时遍历多个范围。它只是简单地将多个范围的元素打包在一起,不进行任何计算或转换。
  • views::zip_transform 则在 views::zip 的基础上,增加了对元素的计算或转换功能。它会将可调用对象应用于每个元组中的元素,并返回计算结果。

5.2 使用场景差异

  • 当你只需要同时遍历多个范围,而不需要对元素进行额外的计算时,使用 views::zip 即可。
  • 当你需要对多个范围的元素进行某种计算或转换时,使用 views::zip_transform 更加合适。

5.3 代码复杂度差异

  • views::zip 的代码相对简单,只需要将多个范围作为参数传递给 views::zip 即可。
  • views::zip_transform 除了需要传递多个范围外,还需要传递一个可调用对象,代码相对复杂一些。

六、总结

views::zipviews::zip_transform 是C++23中非常实用的两个特性,它们基于Ranges库,为处理多个范围的数据提供了更加便捷和高效的方式。views::zip 可以将多个范围的元素组合在一起,方便同时遍历;views::zip_transform 则可以对多个范围的元素进行计算或转换,进一步扩展了功能。

在实际开发中,我们可以根据具体的需求选择使用 views::zipviews::zip_transform 。同时,我们也可以将它们与其他Ranges库的工具函数结合使用,实现更加复杂的数据处理逻辑。随着C++23的不断普及和应用,这些新特性将逐渐得到更多的关注和使用,帮助开发者编写出更简洁、高效、易读的代码。

相关文章:

  • [传输层]TCP协议
  • Node.js 中的 URL 模块
  • 医疗系统开发架构和技术路线建议-湖南某三甲医院
  • 开源模型应用落地-qwen模型小试-Qwen3-8B-融合VLLM、MCP与Agent(七)
  • TikTok矩阵运营干货:从0到1打造爆款矩阵
  • WM_TIMER定时器消息优先级低,可能会被系统丢弃,导致定时任务无法正常执行
  • 论软件设计模式及其应用
  • 25.5.13
  • PyTorch中的nn.Embedding应用详解
  • 【架构】RUP统一软件过程:企业级软件开发的全面指南
  • 为什么hadoop不用Java的序列化?
  • ThingsBoard使用Cassandra部署时性能优化
  • React19源码系列之 API(react-dom)
  • Spring Boot配置文件
  • Spring Boot 项目中什么时候会抛出 FeignException?
  • dockerdesktop 重新安装
  • Spring Boot中HTTP连接池的配置与优化实践
  • 解决 MinIO 对象存储“AccessDenied”问题及 Docker 操作全解析
  • Kotlin 中的作用域函数
  • 配置Hadoop集群-上传文件
  • 学习教育期间违规吃喝,李献林、叶金广等人被通报
  • 山东省市监局“你点我检”专项抽检:一批次“无抗”鸡蛋农兽药残留超标
  • 牛市早报|中美日内瓦经贸会谈联合声明公布
  • 技术派|更强的带刀侍卫:从054B型战舰谈谈世界护卫舰发展
  • 最高降价三成,苹果中国iPhone开启大促销,能拉动多少销量?
  • 科创板年内第3家!健信超导IPO获受理,拟募资8.65亿