现代C++如何无需容器使用带par_unseq的std::for_each
问题:在现代C++中无需容器,直接使用带
std::execution::par_unseq的std::for_each? 希望以标准C++方式实现并行执行(不依赖TBB、Boost或微软特定实现),不想像当前这样创建虚拟容器:
const int amount_of_iterations = 10; std::vector<int> dummy(amount_of_iterations); std::for_each(std::execution::par_unseq, dummy.begin(), dummy.end(), [&](int& item) { int idx = int(&item - &(*dummy.begin())); foo(idx); });
是否有更便捷方式,比如计数迭代器、伪容器等?
更新
尝试了std::views::iota方案,但无法运行:
auto r = std::ranges::views::iota(0, 10); std::for_each(std::execution::par_unseq,r.begin(), r.end(), [&](int& item) { int idx = int(&item - &(*r.begin())); foo(idx); });
报错:
error C2102: '&' requires l-value
因此有两个问题:
- 原代码获取索引的方式是否最优(安全、直接等),是否有更好方案?
- 如何让基于范围视图的方案正常运行?
解答
问题1:原代码获取索引的方式是否最优?
原代码通过指针减法计算索引的方式不安全,核心问题在于:
- 该方式依赖容器的连续内存布局和随机访问迭代器特性,仅对
std::vector这类容器有效,若后续更换容器类型(如std::deque)会直接触发未定义行为。 - 代码逻辑冗余,明明需要的是索引,却先通过元素再反向推导,完全没必要。
推荐两种更安全、直接的方案:
方案1:用std::views::iota直接生成索引序列
const int amount_of_iterations = 10; auto indices = std::ranges::views::iota(0, amount_of_iterations); std::for_each(std::execution::par_unseq, indices.begin(), indices.end(), [&](int idx) { foo(idx); });
iota视图直接生成从0到指定值的整数序列,lambda直接接收索引值,无需任何额外计算。
方案2:用std::counting_iterator(C++20+)
如果偏好迭代器而非范围视图,可使用标准库的计数迭代器:
#include <iterator> const int amount_of_iterations = 10; auto begin = std::counting_iterator<int>(0); auto end = std::counting_iterator<int>(amount_of_iterations); std::for_each(std::execution::par_unseq, begin, end, [&](int idx) { foo(idx); });
问题2:如何让基于范围视图的方案正常运行?
你之前的代码有两个致命问题:
std::views::iota生成的是临时右值,无法取地址(这就是报错C2102: '&' requires l-value的原因);- 完全没必要通过地址计算索引——
iota本身就是生成索引的,直接用即可。
修正后的代码如下:
auto r = std::ranges::views::iota(0, 10); // lambda参数改为int(而非int&),直接接收索引值 std::for_each(std::execution::par_unseq, r.begin(), r.end(), [&](int idx) { foo(idx); });
更简洁的C++20范围版本:
std::ranges::for_each(std::execution::par_unseq, std::ranges::views::iota(0, 10), [&](int idx) { foo(idx); });
关键注意事项
std::execution::par_unseq要求迭代器满足随机访问迭代器要求,std::views::iota和std::counting_iterator均满足该条件,完全适配并行执行需求;- 永远避免依赖内存布局的指针减法操作,标准库提供的索引生成工具是更可靠的选择。
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

