opNext: Simplified ranges
Paul Backus
snarwin at gmail.com
Sat Nov 5 18:08:39 UTC 2022
On Saturday, 5 November 2022 at 15:17:42 UTC, Steven
Schveighoffer wrote:
> This can be solved by a wrapper:
>
> ```d
> struct RefOf(T)
> {
> private T *_val;
> ref T _get() { return *_val; }
> alias _get this;
> }
>
> auto refOf(T)(return ref T val) { return RefOf!T(&val); }
>
> foreach(elem; range.refOf) // now doesn't make a copy.
> ```
You'd think, but if you actually try this, it turns out it
doesn't work: the compiler is "smart" enough to see through the
`alias this`, and makes a copy of `range.refOf._get` (the actual
range object) instead of `range.refOf` (the wrapper).
So, for example, this usage code prints `[1, 2, 3]`,
demonstrating that the range is *not* consumed by the `foreach`
loop:
```d
void main()
{
import std.range, std.stdio;
auto r = only(1, 2, 3);
foreach (e; refOf(r)) {}
writeln(r);
}
```
In the `-vcg-ast` output, you can see the call to `_get` inserted
by the compiler:
```d
void main()
{
import std.range;
import std.stdio;
OnlyResult!(int, int, int) r = only(1, 2, 3);
{
OnlyResult!(int, int, int) __r47 = refOf(r)._get().opSlice();
for (; !__r47.empty(); __r47.popFront())
{
int e = __r47.front();
}
}
writeln(r);
return 0;
}
```
More information about the Digitalmars-d
mailing list