如何用现代C++简洁遍历vector等容器的子范围?
现代C++实现数组中间元素遍历的简洁写法
针对你要遍历数组a中从索引1到n-2(即跳过第一个和最后一个元素)的需求,下面是几种基于现代C标准(尤其是C20/23 Ranges)的简洁实现:
一、C++20 及以上:Ranges 库写法
Ranges 是现代C++中处理序列的核心工具,能让代码更简洁直观,避免手动管理索引或迭代器边界。
1. drop + take 组合(C++20 可用)
通过跳过第一个元素,再截取后续的n-2个元素,完美匹配原循环的范围:
#include <ranges> double a[N]; int n = ...; // 数组的有效元素个数 for (auto& elem : a | std::views::drop(1) | std::views::take(n - 2)) { // 对elem执行操作,例如:elem += 1.0; }
2. subrange 直接构造子范围(C++20 可用)
手动指定迭代器的起始和结束位置,适合需要复用这个中间范围的场景:
#include <ranges> double a[N]; int n = ...; // 构造从a[1]到a[n-2]的子范围(结束迭代器是a + n -1,开区间) auto middle_elements = std::ranges::subrange(std::begin(a) + 1, std::begin(a) + n - 1); for (auto& elem : middle_elements) { // 操作elem }
3. views::slice(C++23 新增,最直观)
C++23 引入的slice视图可以直接通过索引区间指定范围,语法和原循环的索引逻辑完全对应:
#include <ranges> double a[N]; int n = ...; // slice(start_idx, end_idx) 是左闭右开区间,正好对应i从1到n-1(不包含n-1) for (auto& elem : a | std::views::slice(1, n - 1)) { // 操作elem }
二、兼容C++11的现代写法(非Ranges)
如果项目还没升级到C++20,用迭代器替代索引循环也是更现代的选择:
#include <iterator> double a[N]; int n = ...; for (auto it = std::begin(a) + 1; it != std::begin(a) + n - 1; ++it) { auto& elem = *it; // 操作elem }
注意事项
- 上述写法对
std::array<double, N>同样适用,C风格数组和标准容器的迭代器/Ranges支持是一致的。 - 当
n <= 2时,所有写法都会自动处理空范围,不会进入循环,和原代码行为完全一致。 - 使用
auto& elem可以直接修改元素,和原代码操作a[i]的效果一致;如果仅读取元素,可改用const auto& elem或auto elem。
内容的提问来源于stack exchange,提问作者vonbrand
相关产品推荐
相关产品推荐

