我知道这个问题听起来很奇怪,所以这里有一些上下文。
最近我很失望地得知,在C ++ 20范围内,map reduce无法像人们期望的那样工作,即
const double val = data | transform(...) | accumulate (...);
不起作用,您必须以以下不自然方式编写它:
const double val = accumulate(data | transform(...));
可以在here和here中找到详细信息,但是可以归结为以下事实:在两个不同的用例之间,累积不能消除歧义。
所以这让我开始思考:
如果C ++ 20要求您必须使用管道来使用范围,那么您也可以不编写
vector<int> v;
sort(v);
但您必须写
vector<int> v
v|sort();
能解决歧义问题吗?
如果是的话,尽管对于使用std::sort
和其他STL算法的人们来说是不自然的,但我想知道从长远来看,这是否是更好的设计选择。
注意: 如果这个问题太含糊,可以自由投票结束,但是我认为这是一个合理的设计问题,可以相对公正地回答,尤其是如果我对问题的理解是错误的。
答案 0 :(得分:4)
您需要区分范围算法和范围适配器。算法是对一系列值执行通用运算的函数。适配器是创建范围视图的功能,这些视图可修改范围的表示形式。适配器由|
运算符链接;算法只是常规功能。
有时,相同的概念性事物可以具有算法和适配器形式。 transform
作为算法和适配器都存在。前者将转换存储到输出范围中。后者会创建输入的视图范围,并根据要求延迟计算转换。
这些是满足不同需求和用途的不同任务。
此外,请注意,C ++ 20中没有sort
适配器。排序适配器必须创建一个以某种方式混合在源范围中的元素周围的视图范围。它必须为新的值序列分配存储空间(即使只是将迭代器/指针/索引排序到值上)。而且排序必须在构造时完成,这样就不会发生懒惰操作。
这也是accumulate
不能这样工作的原因。这不是“模棱两可”的问题;这是行动的基本性质。累加计算范围内的值;它不会从现有范围计算出新范围。那是算法的工作,而不是适配器的工作。
某些任务以算法形式有用。有些任务以适配器形式有用(您发现很少有类似zip
的算法)。某些任务在这两者中都是有用的。但是,由于这是两个用于不同目的的独立概念,因此它们具有不同的调用方式。
答案 1 :(得分:1)
能解决歧义问题吗?
是的
如果只有一种写东西的方法,那一种方法必须是唯一可能的解释。如果算法“调用”只能是必须用|
操作完成且部分在左侧的算法的部分调用,那么您根本就不会有算法是否存在的问题通话是部分通话或全部通话。只是总是局部的。
从这个意义上说,没有歧义。
但是,如果您走了那条路线,最终会遇到以下情况:
auto sum = accumulate("hello"s);
实际上并没有对字符串中的char
求和,实际上是占位符,它正在等待范围内的初始值"hello"s
的累加。