https://issues.dlang.org/show_bug.cgi?id=5351
Simen Kjaeraas <[email protected]> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |[email protected] --- Comment #3 from Simen Kjaeraas <[email protected]> --- The implementation above will fail for this simple case: MyRange!int a = [1,2,3]; a.popFront(); assert(a[0] == a.front); It could be made to work for ranges that support slicing, and assignment from the slice to the range: void popFront() { this = this[1..$]; } front and empty are then trivial calls to this[0] and length == 0, respectively. One option that only requires opIndex and length would use a wrapper struct. This solution would leave MyRange as a non-range, though - only its sliced result would be a range: struct MyRange(T) { T[] arr; T opIndex(size_t idx) { return arr[idx]; } @property size_t length() { return arr.length; } mixin rangeFuncs!(); } template rangeFuncs() { auto opSlice() { alias TT = typeof(this); struct Result { size_t _index; TT* _range; auto front() { return (*_range)[_index]; } @property bool empty() { return _index == _range.length; } void popFront() { _index++; } auto opIndex(size_t idx) { return (*_range)[_index + idx]; } } Result result; result._range = &this; return result; } } unittest { import std.range.primitives : isInputRange; import std.algorithm.comparison : equal; auto a = MyRange!int([1,2,3,4]); static assert(!isInputRange!(typeof(a))); static assert(isInputRange!(typeof(a[]))); assert(a[].equal([1,2,3,4])); } In conclusion, opIndex + length is insufficient functionality to turn something into a range. --
