std.algorithm.find是否需要范围元素的引用?
我一直在研究基于类的有限随机访问范围。对其执行一些测试时:std.algorithm.find是否需要范围元素的引用?,d,phobos,D,Phobos,我一直在研究基于类的有限随机访问范围。对其执行一些测试时: auto myRange = /* construct my range */ static assert (isRandomAccessRange!(typeof(myRange))); // static assert (!isInfinite!(typeof(myRange))); // both pass auto preamble = myRange[0..128]; assert( all!"a == 0
auto myRange = /* construct my range */
static assert (isRandomAccessRange!(typeof(myRange))); //
static assert (!isInfinite!(typeof(myRange))); // both pass
auto preamble = myRange[0..128];
assert( all!"a == 0"(preamble)); // check for all zeros
我在GDC4.9.2中得到了这个编译错误,关于上面代码段的最后一行:“algorithm.d | 4838 | error:foreach:cannotmakee ref”
错误指向std.algorithm.find
(find_if变量,取范围和谓词)中的这段代码,它确实使用foreach
引用每个元素:
InputRange find(alias pred, InputRange)(InputRange haystack)
if (isInputRange!InputRange)
{
alias R = InputRange;
alias predFun = unaryFun!pred;
static if (isNarrowString!R)
{
...
}
else static if (!isInfinite!R && hasSlicing!R && is(typeof(haystack[cast(size_t)0 .. $])))
{
size_t i = 0;
foreach (ref e; haystack) // <-- needs a ref
{
if (predFun(e))
return haystack[i .. $];
++i;
}
return haystack[$ .. $];
}
else
{
...
}
}
我可以改变这一点,但真正困扰我的是,现在range类符合函数的先决条件,foreach
iteration仍然应该使用它们。引用文件:
对结构和类对象的迭代可以通过范围来完成。对于foreach
,这意味着必须定义以下属性和方法:
特性:
如果没有更多元素,则返回true.empty
返回范围中最左边的元素.front
将范围的左边缘向右移动一步.popFront()
opApply
成员函数定义,foreach_反向行为由特殊的opApplyReverse
成员函数定义。这些功能具有以下类型:
int-opApply(int-delegate(ref类型[,…])dg)代码>
根据我的理解,这是不应该被寻找的
还引用了std.algorithm.all
,这似乎也不需要迭代引用:
bool all(Range)(Range-Range)if(isInputRange!Range&&is(typeof(unaryFun!pred(Range.front)))代码>
当且仅当
在输入范围中找到的所有值v都满足谓词
pred。对pred执行(最多)Б(范围.长度)评估
那么这是不是Phobos库中的一个bug,std.algorithm.find
首先应该按值进行迭代?或者我遗漏了什么?在一个应该是范围的对象上声明opApply
是没有意义的,因为如果它是范围,那么基于范围的函数将用于foreach
,而不是opApply
。当然,如果对范围类型调用的是opApply
,而不是front
、popFront
和empty
,那么这就是编译器错误。从声音上看,编译器错误地选择了opApply
,因为opApply
使用了ref
,而front
没有。但是,只要未声明opApply
,使用ref
的foreach
的front
就可以正常工作。因此,ref
与其说是一个问题,不如说是编译器在看到opApply
有ref
而front
没有时错误地使用了opApply
因此,需要修复编译器,但这可能以前从未被发现,因为像您这样在范围类型上声明opApply
是没有意义的。因此,我认为您的代码需要更改为不在范围类型上声明opApply
。这样你就不会碰到这个特殊的错误了
也就是说,Phobos中讨论的代码对于引用类型(如类)的范围来说是有缺陷的,因为它在haystack
上迭代时无法调用save
。其结果是原始范围发生了变异,以引用正在搜索的点,而返回的点远超过了正确的点,就像元素来自干草堆前面一样。因此,即使您停止声明opApply
和/或编译器错误得到修复,如果您使用范围的引用类型,std.algorithm.find也需要修复,代码才能开始工作
编辑:
好的。那不太对。在与一些编译器开发人员讨论时,我得到了纠正。过去,范围函数优于opApply
,这就是规范所说的,但在某些时候,它被更改为opApply
优于范围函数,因此范围类型可以使用opApply
与foreach
进行迭代,如果这对它更有效的话(虽然这显然会带来范围函数和opApply
不具有相同行为的风险,这可能会导致一些非常严重的错误)。因此,规范与编译器的当前行为不匹配,您可以在范围类型上声明opApply
(尽管我仍然建议不要这样做,除非你从中获得了明确的性能增益)
也就是说,这里出现错误的事实仍然是一个编译器错误。因为您的opApply
没有使用ref
,它不能与ref
循环变量一起工作,而范围函数会,因此在这种情况下,编译器应该调用范围函数,显然不是。无论如何,这都是错误的“以前没有发现过,因为几乎没有人在范围上使用opApply
,因为这样做的唯一原因是这样做是否会提高性能,而且我确信,事实上规范仍然说范围函数比opApply
更受欢迎,这使得尝试过它的人比ca更少se.的确,那是奈尔
int opApply(int delegate(E) f) {...}
int opApply(int delegate(size_t,E) f) {...}