【发布时间】:2021-07-13 23:21:55
【问题描述】:
取自 range-v3 文档,以下示例演示了一个简单的 views 组合,以流水线方式生成 range:
std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace ranges;
auto rng = vi | views::remove_if([](int i){return i % 2 == 1;})
| views::transform([](int i){return std::to_string(i);});
我知道views::foo 等同于foo_view(),因此上面的示例最终如下:
transform_view(remove_if_view(vi, <lambda>), <lambda>)
现在的问题是:
remove_if 和 transform 操作的顺序是如何发生的? (我知道他们是懒惰的,他们实际上并没有在这一步计算,而不是稍后当 rng 实现时,但这不是重点)。
我可以在这里看到两个选项:
-
这些操作由 range-v3 融合,当通过某个迭代器访问
rng的给定元素时,这两个操作将应用于该元素。 -
当请求给定元素时,整个
remove_if操作将应用于整个vi,然后将该操作的输出向量输入transform。因此,我们最终得到了一个完整的“trasformed + removed_if”向量,它使我们能够访问所需的元素。
我很确定选项 (1) 是实际发生的情况。如果是这样的话,range-v3 是如何做到这一点的呢?它是否有某种通用的组合代码来组合无限数量的组合视图操作?
附带问题:range-v3 视图公开了什么样的迭代器?我认为random-access 迭代器以下的任何内容都会使并行化变得不可能。
元问题:如果选项 (1) 是真的,那么并行化range-algorithms 是不是非常简单,因为它们将一个简单的范围(由多个视图组成,通过操作融合按需计算)作为输入)?
【问题讨论】:
-
不,并行化范围算法并不容易。忘掉实现吧,你如何选择一个范围内的线程分布,这个范围可以由filter、take_first_n、reverse等任意顺序的操作组成?
-
我猜想在
take_first_n | reverse上进行一个简单的fork-join 会完成这项工作吗?另外,还有更多富有成效的例子,如果并行化会带来性能提升(就像我所指的那样,在我的问题中) -
好吧,range-v3 是open source 如果你觉得它很琐碎,你可以去尝试并行化它,或者你可以用幼稚的方法来做。
-
这个问题有很多。你基本上是问
views::remove_if和views::transform是怎么实现的? -
@Barry 我在问它们是如何作为参考示例实现的。主要问题是从流水线视图派生的范围一般是如何实现的。
标签: c++ std c++20 range-v3 std-ranges