我一直在研究基于类的有限随机访问范围。在对其进行一些测试时:
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
我在 GDC 4.9.2 中遇到了这个编译错误,关于上面片段中的最后一行:“algorithm.d|4838|error: foreach: cannot make e 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
{
...
}
}
这很可能发生,因为我提供了一个opApply
不提供ref
参数的实现(该类也不ref
向任何其他成员函数提供返回类型)。
int opApply(int delegate(E) f) {...}
int opApply(int delegate(size_t,E) f) {...}
我可以改变它,但真正困扰我的是,现在范围类符合函数的先决条件,并且foreach
迭代仍然应该与它们一起工作。从文档中引用:
结构和类对象的迭代可以用范围来完成。对于
foreach
,这意味着必须定义以下属性和方法:特性:
.empty
如果没有更多元素,则返回 true.front
返回范围的最左边的元素方法:
.popFront()
将范围的左边缘向右移动一位
所有这些都提供了(否则它不会是随机访问范围),所以它应该使用它们。相反,它可能正在寻找下面描述的替代迭代方法:
如果聚合表达式是结构或类对象,并且范围属性不存在,则 foreach 由特殊
opApply
成员函数定义,foreach_reverse 行为由特殊opApplyReverse
成员函数定义。这些函数具有以下类型:
int opApply(int delegate(ref Type [, ...]) dg);
根据我的解释,不应该寻找。
也 quoting std.algorithm.all
,这似乎也不需要迭代引用:
bool all(Range)(Range range) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))));
当且仅当在输入范围范围内找到的所有值 v 都满足谓词 pred 时返回 true。(至多)对 pred 执行 Ο(range.length) 评估。
那么这是 Phobos 库中的一个错误,std.algorithm.find
应该首先按值迭代吗?还是我错过了什么?