Я работаю над конечным диапазоном произвольного доступа на основе классов. При выполнении нескольких тестов на нем:
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|ошибка: foreach: невозможно сделать 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);
Что, в моей интерпретации, не следовало искать.
Также цитируя std.algorithm.all
, который, похоже, также не требует итерации для ссылок:
bool all(Range)(Range range) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))));
Возвращает true тогда и только тогда, когда все значения v, найденные во входном диапазоне, удовлетворяют предикату pred. Выполняет (максимум) Ο(range.length) оценок pred.
Так это ошибка в библиотеке Phobos, и std.algorithm.find
должен в первую очередь выполнять итерацию по значению? Или есть что-то, что я пропустил?