コンパイラがforeachに遭遇した場合
foreach (element; range) {
それは内部的に次のような書き換えられます:
for (auto it = range; !it.empty; it.popFront()) { auto element = it.front; ... }
上記のインタフェースを満たすオブジェクトはすべて入力範囲と呼ばれ、繰り返し処理できる型です:
struct InputRange {
@property bool empty();
@property T front();
void popFront();
}