You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

现代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. 原代码获取索引的方式是否最优(安全、直接等),是否有更好方案?
  2. 如何让基于范围视图的方案正常运行?

解答

问题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:如何让基于范围视图的方案正常运行?

你之前的代码有两个致命问题:

  1. std::views::iota生成的是临时右值,无法取地址(这就是报错C2102: '&' requires l-value的原因);
  2. 完全没必要通过地址计算索引——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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 02:20:55