为什么并行的for_each需要前向迭代器?

时间:2019-03-22 16:42:58

标签: c++ language-lawyer std c++17 c++-standard-library

我正在设计一个遍历多个容器的迭代器,因此将代理对象作为返回类型。因此,最好的办法是成为输入迭代器(这是因为前向迭代器要求reference是实际的引用类型,而据我所知,这对输入迭代器而言并非如此)。

(让我说)普通for_each就像我的迭代器一样具有魅力。
但是,当我查看其并行版本时,我发现它仅接受转发迭代器。因此,我不能使用复杂的迭代器来返回代理对象,这很烦人。
另一方面,我在网上寻找其他值得注意的实现方式,但这并不像我最初想象的那么普遍-例如,英特尔®TBB为每个接受输入迭代器的应用程序提供了自己的并行处理。

然后我的问题是:为什么并行std::for_each不能与输入迭代器一起使用?
我看不到它们是正向迭代器的意义,因为乍一看它即使在输入迭代器中也能正常工作。我想念什么?

2 个答案:

答案 0 :(得分:10)

由于您指出的原因,C ++ 17迭代器模型存在一个已知缺陷,即代理迭代器只能是输入迭代器。这有很多缺点。并行算法不需要非代理迭代器,但是肯定需要多遍保证。并且当前的迭代器类别模型将两者合并。

使用C ++ 20范围,我们得到iterator_concept的概念,它是向后兼容的填充程序,可以正确地支持代理迭代器。例如,您可以拥有iterator_category的{​​{1}}到input_iterator_tag的{​​{1}}。新的ForwardIterator概念不是针对类别,而是针对以下概念:

iterator_concept

并行算法是否会改变是另一个我无法回答的问题。

答案 1 :(得分:4)

C ++ 17迭代器概念将前向迭代器定义为迭代器的最弱形式,它需要在相同范围内运行多个迭代器。也就是说,您可以复制正向迭代器,增加副本,但仍可以通过原始迭代器访问原始值。

纯IntputIterator概念仅需要单遍。递增迭代器后,该迭代器的所有其他副本实际上将变得无效。

要能够并行化const intersection = (a1 = [], a2 = []) => { const s = new Set(a1) return a2.filter(x => s.has(x)) } const intersectAll = (a = [], ...more) => more.reduce(intersection, a) console.log(intersectAll(['a', 'b'], ['b', 'c'], ['b', 'd'], ['e', 'b'])) // [ 'b' ],最终需要每次并行调用才能获得一组独特的迭代器和值进行操作。这意味着迭代器必须是可复制的并且独立于其他迭代器。这就要求它们成为正向迭代器。

现在是的,这意味着即使迭代器 彼此独立,也不能使用具有并行for_each的代理迭代器。这只是C ++ 17迭代器概念模型的局限性。