为什么范围不能用于管道库功能?


10

乔纳森博卡拉(作者流利C ++)写了一个叫做库的管道

存储库主页上说的“管道”与范围的使用不同,尽管看起来相同:它不是基于惰性拉动,而是急于推动。但有人指出,不能使用范围库执行各种“管道”操作。例如:

  • 解压缩-采取一个压缩输入-本质上是一系列k元组-并产生k个独立的独立输出。
  • fork-产生容器/范围的多个(独立)副本。

我不太明白原则上为什么会这样。(当然,除了无法获得最终迭代器/前哨的范围之外。)

Answers:


7

实际上,讨论的是基于推的处理方法与基于拉的处理方法之间的区别。在类似此管道库的推送系统中,您建立了一个处理链,每个处理步骤将其数据直接推送到下一个。在类似范围的拉式系统中,您可以建立数据表示形式,可以根据需要访问和修改数据。处理本身不是发生的。它仅在有人尝试消耗范围时发生。

unzipfork操作都是一个一对多的操作:他们把一个单一的输入,并将其映射到多个处理操作。

作为推送系统,管道库由于其API的结构而可以处理一对多操作。操作由函数调用表示;输入由使用点隐含(使用>>=或传递给处理器)。函数的参数定义其输出(忽略用于处理器本身的参数)。而且由于C ++函数可以具有任意数量的参数,因此自然会发生一对多映射操作。您只需为各种输出提供适当的处理器即可。

作为拉动系统,范围基于返回值。C ++没有返回多个值的语言机制,因此我们能做的最好的就是返回一个表示多个值的“值”。

但是,范围适配器链接最终基于输入为range。并且“代表多个值的'值' 本身不是范围。它可能包含范围,但是并没有使其成为范围。

因此,现在您必须采用这种绝对不是“范围”的类型,并使所有范围适配器都可以使用它。应用范围适配器必须在整个类型中广播该操作,从而创建多对多操作。这样做并不容易。

但更重要的是……那可能不是您想要的。如果fork是范围,则几乎可以肯定要对复制的范围进行不同的处理。这完全关闭了使用该|操作执行此操作的任何机会。您将必须构建将适配器应用于这些范围元组的特定部分的方法。而且这些方式越来越像基于推送的处理器。

最终,拉式系统在每个级别上只有一个输出。那只是这种API核心概念的一部分:每个处理步骤都会生成一个范围。这具有优势(延迟处理),但是代表一对多操作是其弱点之一。

范围当然可以具有unzip功能(fork实际上只是复制范围)。但这不是|样式适配器。这将是一个在某种可分解类型上获取范围并返回范围元组的函数。如果要对它们进行更多处理,则需要将元组存储在一个值中,访问各个元素,并根据需要使用它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.