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

C++23 views::chunk_by (P2443R1) 详解

文章目录

    • 引言
    • C++23 范围库概述
      • 范围视图(Range Views)
      • 范围算法(Range Algorithms)
      • 范围适配器(Range Adapters)
    • std::views::chunk_by 介绍
      • 基本概念
      • 特性
      • 使用场景
    • 示例代码
      • 简单示例
      • 自定义谓词示例
    • 总结

引言

在C++的发展历程中,每一个新版本都会带来一些令人期待的特性和改进。C++23作为C++20的增量更新,聚焦于简化代码、增强类型安全和填补功能缺口。其中,std::views::chunk_by 作为范围适配器的新成员,为我们处理数据序列提供了更加便捷和高效的方式。本文将详细介绍 std::views::chunk_by 的基本概念、特性、使用场景以及示例代码。

C++23 范围库概述

在深入了解 std::views::chunk_by 之前,我们先来简单回顾一下C++20引入的范围库(Ranges library)。范围库是C++20的一个主要组成部分,它提供了一种新的方法来处理容器中的元素序列,使得代码更加简洁和可读。范围库主要包含以下几个关键概念:

范围视图(Range Views)

范围视图提供了一种不修改原始数据的情况下,对容器进行变换、过滤和切片的能力。常见的视图包括 std::views::allstd::views::filterstd::views::transform 等。例如:

#include <iostream>
#include <vector>
#include <ranges>int main() {std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};auto even_numbers = vec | std::views::filter([](int x) { return x % 2 == 0; });auto squared = even_numbers | std::views::transform([](int x) { return x * x; });auto first_three = squared | std::views::take(3);for (int x : first_three) {std::cout << x << " ";}// 输出: 4 16 36 return 0;
}

范围算法(Range Algorithms)

C++20引入了新的范围版本的算法,这些算法可以直接在范围对象上操作,而不需要显式循环。例如 std::ranges::sortstd::ranges::find 等。示例如下:

#include <iostream>
#include <vector>
#include <ranges>int main() {std::vector<int> vec = {5, 3, 1, 4, 2};std::ranges::sort(vec);std::cout << "Sorted vector: ";for (int x : vec) {std::cout << x << " ";}// 输出: Sorted vector: 1 2 3 4 5 auto min_val = std::ranges::min(vec);std::cout << "\nMinimum value: " << min_val << std::endl;// 输出: Minimum value: 1 return 0;
}

范围适配器(Range Adapters)

范围适配器类似于视图,但它们通常用于创建新的范围对象。常见的适配器包括 std::ranges::views::joinstd::ranges::views::chunk_by_size 等。

std::views::chunk_by 介绍

基本概念

std::views::chunk_by 是C++23中引入的一个范围适配器,它接受一个视图和一个可调用对象(二元谓词),并通过在每对相邻元素之间拆分底层视图来生成一个子范围(块)的视图。对于这些元素,谓词返回 false。每对元素中的第一个元素属于前一个块,第二个元素属于下一个块。

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

template< ranges::forward_range V, std::indirect_binary_predicate<iterator_t<V>, ranges::iterator_t<V>> Pred >requires ranges::view<V> && std::is_object_v<Pred>
class chunk_by_view: public ranges::view_interface<chunk_by_view<V, Pred>> (since C++23)
namespace views {inline constexpr /* unspecified */ chunk_by = /* 未指定 */ ;
} (since C++23)

特性

  • 谓词而非等价关系:与D语言的 chunkBy 不同,std::views::chunk_by 不要求谓词是一个等价关系。例如,D的 chunkBy 要求谓词满足自反性、对称性和传递性,而 std::views::chunk_by 则没有这个限制。
  • 不支持输入范围:由于 chunk_by 需要对相邻元素计算谓词,因此它要求底层范围是前向范围(forward range)。缓存元素不是一种可行的方法,主要原因在 [P2321R2] 的第4.3.4节中有讨论。
  • 范围属性:如果底层范围是双向范围(bidirectional range),则 chunk_by 也是双向范围;否则,它是前向范围。如果底层范围是通用范围(common range),则 chunk_by 也是通用范围。它永远不会是借用范围(borrowed range)或有大小范围(sized range)。
  • 缓存机制:类似于 splitchunk_by 在其 begin 中计算第一个范围的末尾并进行缓存,以满足摊销的 O ( 1 ) O(1) O(1) 要求。这意味着它不支持常量迭代。

使用场景

std::views::chunk_by 适用于需要将一个序列按照某种规则进行分组的场景。例如,将一个整数序列按照奇偶性进行分组,或者将一个字符串序列按照长度进行分组等。

示例代码

简单示例

#include <iostream>
#include <vector>
#include <ranges>
#include <fmt/core.h>int main() {std::vector<int> v = {1, 2, 2, 3, 0, 4, 5, 2};fmt::print("{}\n", v | std::views::chunk_by(std::ranges::less_equal{}));   // [[1, 2, 2, 3], [0, 4, 5], [2]]return 0;
}

在这个示例中,我们使用 std::views::chunk_bystd::ranges::less_equal{} 谓词将整数序列 v 进行分组。当相邻元素不满足小于等于关系时,就会进行分组。

自定义谓词示例

#include <iostream>
#include <vector>
#include <ranges>
#include <fmt/core.h>int main() {std::vector<int> v = {1, 3, 5, 2, 4, 6, 7, 9};auto is_odd = [](int x) { return x % 2 == 1; };auto chunked = v | std::views::chunk_by([&is_odd](int a, int b) { return is_odd(a) == is_odd(b); });for (const auto& chunk : chunked) {for (int x : chunk) {std::cout << x << " ";}std::cout << std::endl;}return 0;
}

在这个示例中,我们自定义了一个谓词 is_odd 来判断一个数是否为奇数。然后使用 std::views::chunk_by 将整数序列按照奇偶性进行分组。

总结

std::views::chunk_by 是C++23范围库中一个非常实用的范围适配器,它为我们处理数据序列提供了更加灵活和高效的方式。通过使用 std::views::chunk_by,我们可以轻松地将一个序列按照某种规则进行分组,而不需要手动编写复杂的循环和逻辑。同时,范围库的惰性求值特性也使得代码更加高效,避免了不必要的计算和内存消耗。在实际开发中,我们可以根据具体的需求灵活运用 std::views::chunk_by 来简化代码,提高开发效率。

http://www.xdnf.cn/news/4865.html

相关文章:

  • 信息系统项目管理师-软考高级(软考高项)​​​​​​​​​​​2025最新(十三)(1)
  • 3D桌面可视化开发平台HOOPS Native Platform,如何实现3D系统快速开发与部署?
  • stm32 debug卡在0x1FFFxxxx
  • OPC UA 介绍及开发示例
  • 【Survival Analysis】【机器学习】【3】deepseek流程图
  • 22、城堡防御工事——React 19 错误边界与监控
  • 如何用Jmeter实现自动化测试?
  • 【MySQL】存储引擎 - FEDERATED详解
  • WPF之静态资源与动态资源
  • 从 AGI 到具身智能体:解构 AI 核心概念与演化路径全景20250509
  • JVM详解
  • 路由组件1
  • 创建没有 TPM 和安全启动的 Windows 11 可启动 USB 驱动器
  • 【MySQL】数据库、数据表的基本操作
  • SIGIR 2025端到端生成式推荐ETEGRec
  • 详解:ai证书有哪些?
  • MCP开发入门
  • C++ stl中的stack和queue的相关函数用法
  • uniapp 百家云直播插件打包失败
  • 在ISOLAR A/B 工具使用UDS 0x14服务清除单个DTC故障的配置
  • 基于大模型的母婴ABO血型不合溶血病全方位预测与诊疗方案研究
  • Java EE初阶——初识多线程
  • 纯净IP,跨境账号稳定的底层逻辑
  • Linux 文件系统中的数据定位:inode 与 dentry 的技术解析
  • CentOS 7 系统下安装 OpenSSL 1.0.2k 依赖问题的处理
  • 学习笔记:黑马程序员JavaWeb开发教程(2025.4.1)
  • [Windows] 东芝存储诊断工具1.30.8920(20170601)
  • 【应急响应】- 日志流量如何分析?
  • 文本框碰撞测试
  • 基 LabVIEW 的多轴电机控制系统