std::ranges::make_subrange本质是将已有迭代器对或容器封装为subrange对象,不复制数据也不检查边界;支持迭代器对(可选count)或容器参数,返回类型依迭代器类别自动推导,const容器产生const subrange。

std::ranges::make_subrange 本质是构造 subrange 对象
它不“创建子范围”这个动作,而是把已有的迭代器对(begin/end)或容器,打包成 std::ranges::subrange 类型——一个轻量、可移动、支持结构化绑定的视图包装器。关键点在于:它本身不复制数据,也不检查边界,只是封装。
- 接受两种常见参数组合:
begin和end迭代器(可选传入count),或直接传入容器(要求容器满足range且有begin()/end()) - 返回类型由迭代器类别自动推导:比如用
std::vector::iterator构造,得到的是subrange<:vector>::iterator></:vector> - 若传入 const 容器或 const 迭代器,得到的
subrange也是 const-qualified,无法用于修改原容器元素
最常用写法:用一对迭代器构造,注意 end 必须可达
这是最可控的方式,尤其适合切片已有容器的某一段。但必须确保 end 可从 begin 到达(即满足 begin ,且在同个容器内),否则行为未定义——<code>subrange 不做运行时校验。
std::vector<int> v = {0, 1, 2, 3, 4, 5};
auto sub = std::ranges::make_subrange(v.begin() + 1, v.begin() + 4); // [1,2,3]
// sub 的类型是 subrange<:vector>::iterator>
</:vector></int>
- 不能写
v.begin() + 10, v.begin() + 5—— 顺序反了,UB - 不能跨容器:比如用
v1.begin()和v2.end(),编译失败(类型不匹配) - 如果需要带计数(如“从 pos 开始取 3 个”),用三参数重载:
make_subrange(it, count),它内部算出 end,同样要求it + count有效
传容器进去看似方便,实则隐含限制
写 std::ranges::make_subrange(v) 等价于 subrange{v.begin(), v.end()},也就是整个容器。它**不能指定起止位置**——这点常被误读。想切片必须显式传迭代器。
- 传
std::array、std::string、std::vector都可以,只要它们是range - 传右值容器(如临时
std::vector{1,2,3})会导致subrange持有悬垂迭代器——因为容器立即销毁,迭代器失效 - 若需延长生命周期,得配合
std::views::all或直接用容器引用,而不是靠make_subrange“保存”容器
和 views::drop / views::take 混用时,别混淆语义
std::ranges::make_subrange 是底层构造工具;而 std::views::drop(n) | std::views::take(m) 是惰性视图适配器链,返回的是 view 类型,不是 subrange。两者目的相似(获取一段),但类型、求值时机、是否可重复遍历都不同。
-
make_subrange构造后立即确定迭代器位置,后续遍历就是原容器那段的直接访问 -
views::drop|take是延迟计算的 view,每次 begin() 都可能重新计算(虽然通常开销小),且不支持随机访问除非底层支持 - 混合使用没问题,但别以为
make_subrange(v | std::views::drop(1))合法——v | views::drop(1)是 view 类型,不是容器,不满足make_subrange的容器重载约束
真正容易被忽略的是:subrange 不是 view,它没有 operator|,也不能直接参与管道组合;要用它进算法,得先确认目标函数接受 range 概念——而 subrange 满足,所以 std::ranges::sort(sub) 是合法的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











