能否用range-v3或标准算法实现vector指定索引元素处理?
核心问题解答
关于range-v3能否通过filter | transform组合实现需求
首先明确结论:不存在语法层面的阻碍,但不能生硬套用管道作用的对象。
- 很多人会下意识把管道的作用对象选错,比如对着原向量
a做filter/transform——但需求本身不需要对a的元素做筛选,所有要修改的位置已经由索引向量b明确定义,完全没必要反过来枚举a的所有元素再判断哪些需要改。 - 要适配
filter | transform的管道逻辑,只需要把管道的输入源换成索引向量b即可:filter层可以用来做索引合法性校验(比如过滤越界的无效索引,避免触发未定义行为)transform层可以把每个索引值映射为原向量a对应位置的可变引用,让后续管道可以直接修改目标值
示例代码:
这种写法完全符合range-v3管道的设计逻辑,没有任何语义上的硬凑。如果不需要做边界校验,甚至可以省略namespace rv = ranges::views; b | rv::filter([&a](int idx) { return idx >= 0 && static_cast<size_t>(idx) < a.size(); }) | rv::transform([&a](int idx) -> int& { return a[idx]; }) | rv::for_each([](int& target) { target *= 10; });filter层,直接完成等价功能。
关于无范围特性的传统STL能否实现该操作
结论非常明确:完全可以实现,甚至不需要任何额外的语法糖支持。
- 很多人对传统STL算法的误解,是觉得算法只能做“输入范围→输出范围”的纯值转换,其实STL最基础的
std::for_each从C++98开始就支持对输入范围的每个元素执行任意自定义操作。 - 最简洁的实现方式就是直接把索引向量
b作为for_each的输入范围,在遍历每个索引时直接修改a的对应元素,代码和原始for循环的逻辑完全等价:#include <algorithm> std::for_each(b.begin(), b.end(), [&a](int idx) { a[idx] *= 10; }); - 这种写法完全符合标准规范,没有任何未定义行为:
std::for_each本身不限制传入的可调用对象的行为边界,只要在迭代过程中不修改输入范围b本身的结构,你在可调用对象里操作a的元素是完全合法的。哪怕是在没有lambda语法的C++98标准中,只要编写一个持有向量a引用的简单函数对象,同样可以用std::for_each完成逻辑,不存在语法层面的障碍。 - 当然你也可以用
std::transform完成同样的功能,但这种写法属于对算法的轻度滥用,可读性远低于for_each:std::transform(b.begin(), b.end(), b.begin(), [&a](int idx) { a[idx] *= 10; return idx; // 仅为满足transform的输出要求,回传原索引值 });
内容的提问来源于stack exchange,提问作者cocheci
相关产品推荐
相关产品推荐

