On Sunday, 5 August 2018 at 14:07:30 UTC, Steven Schveighoffer
wrote:
I have found something that looks like a bug to me, but also
looks like it could simply be a limitation of the foreach
construct.
Consider this code:
struct Foo {}
enum isFoo(alias x) = is(typeof(x) == Foo);
void main()
{
Foo foo;
assert(isFoo!foo);
static struct X { int i; Foo foo; }
X x;
foreach(i, ref item; x.tupleof)
static if(is(typeof(item) == Foo)) // line A
static assert(isFoo!item); // line B
else
static assert(!isFoo!item);
}
Consider just the two lines A and B. If you saw those lines
anywhere, given the isFoo definition, you would expect the
assert to pass. But in this case, it fails.
What is happening is that the first time through the loop, we
are considering x.i. This is an int, and not a Foo, so it
assigns false to the template isFoo!item.
The second time through the loop on x.foo, the compiler decides
that it ALREADY FIGURED OUT isFoo!item, and so it just
substitutes false, even though the item in question is a
different item.
So is this a bug? Is it expected? Is it too difficult to fix?
The workaround of course is to use x.tupleof[i] when
instantiating isFoo. But it's a bit ugly. I can also see other
issues cropping up if you use `item` for other meta things.
-Steve
Another workaround would be
´´´
void main()
{
Foo foo;
assert(isFoo!foo);
static struct X { int i; Foo foo; }
X x;
static foreach(i, item; typeof(x).tupleof)
static if(is(typeof(item) == Foo)) // line A
static assert(isFoo!item); // line B
else
static assert(!isFoo!item);
}
´´´
wouldn't it?