The following code
import std.algorithm.iteration : filter;
import std.algorithm.mutation : move;
import std.range : iota;
static private struct S
{
import core.memory : GC;
@disable this(this);
this(int x)
{
_ptr = cast(typeof(_ptr))GC.malloc((*_ptr).sizeof);
*_ptr = x;
}
~this() { GC.free(_ptr); } // scoped destruction
@property auto ref value() @safe pure nothrow @nogc { return
*_ptr; }
alias value this;
int* _ptr;
}
auto below1(size_t n,
S s = S.init)
{
// this could work, if the compiler could infer that
// `s` can be implicitly converted to an r-value
return 0.iota(n).filter!(_ => _ < s);
}
auto below2(size_t n,
S s = S.init)
{
// this should work, because `s` is an r-value
return 0.iota(n).filter!(_ => _ < s.move());
}
unittest
{
S s = S(42);
s.value = 43;
s.value = 42;
assert(s.value == 42);
// both these fail
100.below1(s.move());
100.below2(s.move());
}
fails to compile with DMD Git master with error message
t_scope.d(23,6): Error: variable t_scope.below.s has scoped
destruction, cannot build closure
It illustrates one the simplest cases where a container-type
cannot be used inside a lambda closure needed by D's great lazy
ranges.
Can somebody explain why not even `below2` compiles eventhough
`s.move()` is inferred to be an r-value?
Until this gets fixed in the compiler, is there something I can
do in the mean-while to make it possible to use instances of `S`
inside of range lambda closures?