为什么并行 for_each 需要前向迭代器?
Why does the parallel for_each require forward iterators?
我正在设计一个遍历多个容器的迭代器,因此有一个 return 类型的代理对象。因此,它能做的最好的事情就是成为一个输入迭代器(这是因为前向迭代器要求 reference
是一个实际的引用类型,而据我所知,这对于输入迭代器来说并非如此)。
(让我说)普通的 for_each
对我的迭代器来说就像一个魅力。
然而,当我查看它的并行版本时,我看到它只接受前向迭代器。因此我不能使用一个复杂的迭代器,它 return 是一个代理对象,这很烦人。
另一方面,我在网上查看了其他值得注意的实现,这并不像我最初想象的那么普遍——例如,英特尔 TBB 为每个接受输入迭代器的人提供了自己的并行。
我的问题是:为什么并行 std::for_each
不能与输入迭代器一起工作?
我看不出它们是前向迭代器的意义所在,因为乍一看,即使使用输入迭代器它也能正常工作。我错过了什么?
由于您指出的原因,C++17 迭代器模型存在一个已知缺陷,即代理迭代器只能是输入迭代器。这有很多缺点。并行算法不需要非代理迭代器,但它们肯定需要多遍保证。而当前的迭代器类别模型将两者混为一谈。
对于 C++20 范围,我们得到了 iterator_concept
, which is a backwards-compatible shim to properly support proxy iterators. You can have an iterator_category
of input_iterator_tag
but an iterator_concept
of forward_iterator_tag
, for instance. The new ForwardIterator
概念的想法,而不是看类别,而是看概念:
template<class I>
concept ForwardIterator =
InputIterator<I> &&
DerivedFrom<ITER_CONCEPT(I), forward_iterator_tag> &&
Incrementable<I> &&
Sentinel<I, I>;
并行算法是否会改变是另一个我无法回答的问题。
C++17 迭代器概念将前向迭代器定义为迭代器的最弱形式,需要同一范围内的多个迭代器才能运行。也就是说,您可以复制前向迭代器,递增副本,但仍然可以通过原始迭代器访问原始值。
纯 IntputIterator 概念只需要单遍。一旦你增加了一个迭代器,它的所有其他副本都变得无效。
能够并行化 for_each
最终需要每次并行调用都获得一组不同的迭代器和要操作的值。这意味着迭代器必须是可复制的并且独立于其他迭代器。这要求它们是前向迭代器。
现在是的,这意味着您不能将代理迭代器与并行 for_each
一起使用,即使您的迭代器 是 彼此独立的。这只是 C++17 迭代器概念模型的局限性。
我正在设计一个遍历多个容器的迭代器,因此有一个 return 类型的代理对象。因此,它能做的最好的事情就是成为一个输入迭代器(这是因为前向迭代器要求 reference
是一个实际的引用类型,而据我所知,这对于输入迭代器来说并非如此)。
(让我说)普通的 for_each
对我的迭代器来说就像一个魅力。
然而,当我查看它的并行版本时,我看到它只接受前向迭代器。因此我不能使用一个复杂的迭代器,它 return 是一个代理对象,这很烦人。
另一方面,我在网上查看了其他值得注意的实现,这并不像我最初想象的那么普遍——例如,英特尔 TBB 为每个接受输入迭代器的人提供了自己的并行。
我的问题是:为什么并行 std::for_each
不能与输入迭代器一起工作?
我看不出它们是前向迭代器的意义所在,因为乍一看,即使使用输入迭代器它也能正常工作。我错过了什么?
由于您指出的原因,C++17 迭代器模型存在一个已知缺陷,即代理迭代器只能是输入迭代器。这有很多缺点。并行算法不需要非代理迭代器,但它们肯定需要多遍保证。而当前的迭代器类别模型将两者混为一谈。
对于 C++20 范围,我们得到了 iterator_concept
, which is a backwards-compatible shim to properly support proxy iterators. You can have an iterator_category
of input_iterator_tag
but an iterator_concept
of forward_iterator_tag
, for instance. The new ForwardIterator
概念的想法,而不是看类别,而是看概念:
template<class I> concept ForwardIterator = InputIterator<I> && DerivedFrom<ITER_CONCEPT(I), forward_iterator_tag> && Incrementable<I> && Sentinel<I, I>;
并行算法是否会改变是另一个我无法回答的问题。
C++17 迭代器概念将前向迭代器定义为迭代器的最弱形式,需要同一范围内的多个迭代器才能运行。也就是说,您可以复制前向迭代器,递增副本,但仍然可以通过原始迭代器访问原始值。
纯 IntputIterator 概念只需要单遍。一旦你增加了一个迭代器,它的所有其他副本都变得无效。
能够并行化 for_each
最终需要每次并行调用都获得一组不同的迭代器和要操作的值。这意味着迭代器必须是可复制的并且独立于其他迭代器。这要求它们是前向迭代器。
现在是的,这意味着您不能将代理迭代器与并行 for_each
一起使用,即使您的迭代器 是 彼此独立的。这只是 C++17 迭代器概念模型的局限性。