私は、クラスベースの有限ランダム アクセス範囲に取り組んできました。それにいくつかのテストを実行するとき:
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()
範囲の左端を 1 つ右に移動する
これらはすべて提供されているので (それ以外の場合はランダム アクセス範囲にはなりません)、それらを使用する必要があります。代わりに、次に説明する別の反復方法を探している可能性があります。
集計式が構造体またはクラス オブジェクトであり、範囲プロパティが存在しない場合、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))));
入力範囲 range で見つかったすべての値 v が述語 pred を満たす場合に限り、true を返します。(最大で) Ο(range.length) 回の pred の評価を実行します。
これは Phobos ライブラリのバグで、std.algorithm.find
そもそも値で反復する必要があるのでしょうか? それとも、私が見逃したことがありますか?