为什么ranges不能用于pipes库功能?

15

Jonathan Boccara(《Fluent C++》的作者)编写了一个名为pipes的库。

该仓库的主页说,这种“管道”不像使用范围那样,尽管看起来很相似:它不是基于惰性拉取,而是饥饿推送。但是声明说,不能使用范围库执行各种“管道”操作。例如:

  • unzip - 采取压缩的输入-基本上是k元组的范围-并产生k个单独的独立输出。
  • fork - 生成容器/范围的多个(独立)副本。

我不太明白为什么在原则上会出现这种情况。(当然除了你无法获取结束迭代器/标记的范围之外。)

1个回答

12
讨论的本质是推动式处理方法和拉动式处理方法之间的区别。在像这个pipes库这样的推送系统中,您建立了一个处理链,每个处理步骤将其数据直接推到下一个处理步骤中。在像ranges这样的拉取系统中,您建立了数据的表示形式,可以根据需要访问和修改它。处理不会自行发生;只有当有人尝试使用范围时才会发生。
"unzip" 和 "fork" 操作都是一对多操作:它们将单个输入映射到多个处理操作。
作为一个推送系统,pipes库可以处理一对多操作,因为其API结构的存在。操作由函数调用表示;输入是通过使用 (使用">>="或将其传递给处理器) 的使用点暗示的。函数的参数定义其输出(忽略用于处理器本身的参数)。由于C++函数可以具有任意数量的参数,因此一个一对多映射操作自然而然地出现了。您只需为各种输出提供适当的处理器即可。
作为拉取系统,ranges基于返回值。C++没有返回多个值的语言机制,因此我们能做的最好的就是返回代表多个值的 "值"。然而,范围适配器链接最终是基于输入是“范围”的。而表示多个值的“'value'”本身不是一个范围。它可能包含范围,但这并不意味着它是一个范围。
因此,现在您必须使用这个明确的“非范围”类型,并使所有的范围适配器与其配合工作。应用范围适配器必须在类型之间广播该操作,创建一对多的操作。这并不容易。
但更重要的是......那可能不是你想要的。如果你分叉了一个范围,那么你几乎肯定希望在复制的范围上进行不同的处理。这完全关闭了使用“|”操作的任何机会。您将不得不构建一些方法来将适配器应用于这些范围元组的特定部分。这些方法越来越像是基于推送的处理器。
在一天结束时,拉式系统每个级别只有一个输出。这是这种API核心概念的一部分:每个处理步骤生成一个范围。这具有它的优点(惰性处理),但代表一对多操作是它的弱点之一。

范围可以使用 unzip 函数(fork 实际上只是复制范围)。但它不会是一个 | 风格的适配器;它将是一个函数,接受某个可分解类型的范围,并返回一个元组范围。如果你想对它们进行更多处理,那么你需要将元组存储在一个值中,访问各个元素,并根据需要使用它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接