On Saturday, 18 February 2023 at 17:16:18 UTC, Steven Schveighoffer wrote:
> This is how isInputRange used to look. The reason it was changed is because the compiler now "sees" the different clauses separated by &&, and will tell you which one failed. When you wrap it like this, it just sees one big constraint.
Makes sense, although I don't get that on my machine with dmd v2.101.0:
import std.range;
int f(R)() if (isInputRange!R) => 2;
int i = f!int;
isinputrange.d(68): Error: template instance `isinputrange.f!int` does not match template declaration `f(R)()`
with `R = int`
must satisfy the following constraint:
` isInputRange!R`
That's it, nothing about why isInputRange failed. Maybe I'm doing something wrong.
Anyway, assuming dmd can use that I wonder if this would work (aside from the inout issue):
template isInputRange(R) {
extern R r; // dummy
enum isInputRange =
is(typeof(R.init) == R) &&
is(typeof({ return r.empty; }()) == bool) &&
(is(typeof(() return => r.front)) ||
is(typeof(ref () return => r.front))) &&
!is(typeof({ return r.front; }()) == void) &&
is(typeof({ r.popFront; }));
}
dmd could still see through the eponymous template to the expression, in theory.
> I actually did get a PR merged. It wasn't as simple as I had written in that blog post, due to the stupid inout
requirement that inout
data can only be used inside a function with an inout
parameter.
OK, so typeof((R r) { return r.empty; } (R.init))
works with inout.
Thanks for the blog post BTW.
> I did start with using lvalueOf!R
, but then realized that since isInputRange
validates that typeof(R.init) == R
, I just used R.init
as the parameter.
Is that validation to detect types with redefined init
? I didn't realize Phobos needs to care about that.