昆仑山

首页 » 问答 » 常识 » 起底CRange令人惊讶的局限性
TUhjnbcbe - 2023/4/12 21:10:00

作者

JonathanBoccara

译者

苏本如责编

胡巍巍

作者注:今天我们收到了一个来自亚历克斯·阿斯塔辛(AlexAstashyn)的客座帖子。Alex是美国国家生物技术信息中心的RefSeq(ReferenceSequence–标准序列)资源的技术负责人。

注:本文所表达的观点是该帖子作者的观点。而且,我自己也不能算是个“range专家”,所以有些与range有关的信息实际上可能是不正确的(如果你发现有任何严重错误,请在下面留下你的评论)。

在本文中,我将讨论我在C++range上遇到的问题和局限性。

我还将介绍我自己开发的库rangeless,它将所有我希望由range实现的功能提炼在一起,使得我能够处理更大范围的有趣的实际应用用例。

序言

和所有爱好面向函数的声明式无状态编程的开发者一样,我原以为ranges非常有前途。然而,在实践中使用它们的尝试,被证明是一个非常令人沮丧的经历。

我一直在尝试用range写出那些对我来说似乎很合理的代码,然而,编译器却不断地打印出一页页让我无法理解的错误消息。最后我意识到了我自己的错误。我原以为range和这样的UNIX管道一样:catfile

grep...

sed...

sort

uniq-c

sort-nr

head-n10,但事实并非如此……

示例:

示例1:Intersperse(插入分隔符)

让我们尝试编写一个view,在输入元素之间插入一个分隔符。

(此功能由range-v3提供,因此我们可以比较一下这些方法的不同)

//inputs:[x1,x2,...xn]//transform:[[x1,d],[x2,d],...[xn,d]]//flatten:[x1,d,x2,d,...xn,d]//droplast:[x1,d,x2,d,...xn]autointersperse_view=view::transform([delim](autoinp){returnstd::arraydecltype(inp),2{{std::move(inp),delim}};})

view::join//alsocalledconcatorflatteninfunctionallanguages

view::drop_last(1);//droptrailingdelim

transform

join上面的合成是对流的一种常见操作,该操作将每个输入转换为一个输出序列,并对结果序列进行展平。

[x]-(x-[y])-[y]

有些语言对此有单独的抽象,例如Elixir语言中的flat_map或LINQ中的SelectMany。

基于最小惊呀的原则,看来上述办法应该奏效。(如果你还没看过这篇演讲,那说明我推荐的力度还不够)。

但是,上面的代码与range-v3一起无法编译通过。出什么事了?结果发现问题在于view::join不喜欢subrange(子范围-返回的集合)是一个作为右值(rvalue)返回的容器这一事实。我想出了以下的技巧:(有时)用这些视图(view)的右值组成视图,所以让我们将容器返回值包装为一个视图!

view::transform([delim](autoinp){returnview::generate_n([delim,inp,i=0]()mutable{return(i++==0)?inp:delim;},2);})

或者,概括地说,我们可以返回一个容器,例如向量,作为其他用例的视图:

view::transform([](intx){autovec=...;returnview::generate_n([i=0,vec=std::move(vec)]()mutable{returnstd::move(vec[i++]);},vec.size());})

view::join//nowjoin

1
查看完整版本: 起底CRange令人惊讶的局限性