www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Enum template with mixin, need 'this'

reply "Meta" <jared771 gmail.com> writes:
The code I currently have is as follows:

import std.stdio;
import std.traits;
import std.typecons;

struct EmbeddedTest
{
     int bits;
}

struct Test
{
     //Other stuff
	
     EmbeddedTest embeddedTest;

     enum isSet(alias bit) = `cast(bool)(embeddedTest.bits & `
                                 ~ bit.stringof ~ `)`;

      property setBits()
     {
         enum Bits = EnumMembers!Bit;
         Nullable!(Bit, Bit.max)[Bits.length] ret;
         foreach (i, bit; Bits)
         {
             if (mixin(isSet!bit))
             {
                 ret[i] = bit;
             }
         }
		
		return ret;
     }
}

enum Bit
{
     bit1 = 0x0001,
     bit2 = 0x0002,
     bit3 = 0x0004,
     bit4 = 0x0008,
}
									
void main()
{
	Test t;
	t.embeddedTest.bits = 0x1;
	foreach (bit; t.setBits)
	{
		if (!bit.isNull)
		{
			writeln(bit);
		}
	}
}

My problem is that I would like to not have to mixin the result 
of Test.isSet at each usage site, but I also want to avoid making 
it a function if possible. I tried to move the mixin into isSet 
like this:


     enum isSet(alias bit) = mixin(`cast(bool)(embeddedTest.bits & 
`
                                 ~ bit.stringof ~ `)`);

This would now break isSet for usage outside of the struct Test. 
However, I don't see why it wouldn't work inside of Test, since 
the mixin expands, for example, to:

     cast(bool)(embeddedTest.bits & bit1)

So `if (isSet!bit1)` becomes `if (cast(bool)(embeddedTest.bits & 
bit1)`. That doesn't work, however. I get an error message saying 
"need 'this' for 'bits' of type 'int'". Is there a way to make 
this work, or am I stuck with the uglier mixin at the usage site?
Dec 24 2014
parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Wed, 24 Dec 2014 17:05:45 +0000
Meta via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

 So `if (isSet!bit1)` becomes `if (cast(bool)(embeddedTest.bits &=20
 bit1)`. That doesn't work, however. I get an error message saying=20
 "need 'this' for 'bits' of type 'int'". Is there a way to make=20
 this work, or am I stuck with the uglier mixin at the usage site?
i don't think that you can cheat like this. ;-) templates aren't macros, and `mixin` inside the template works immediately. i.e. it's trying to *execute* the mixined code in compile time. so your template with `mixin` in it tries to check `embedded.bits` in *compile* time, and then complains about missing 'this', as it should. i don't think that you can do c-like macros in D.
Dec 24 2014
next sibling parent reply "Meta" <jared771 gmail.com> writes:
On Wednesday, 24 December 2014 at 17:41:09 UTC, ketmar via 
Digitalmars-d-learn wrote:
 On Wed, 24 Dec 2014 17:05:45 +0000
 Meta via Digitalmars-d-learn 
 <digitalmars-d-learn puremagic.com> wrote:

 So `if (isSet!bit1)` becomes `if (cast(bool)(embeddedTest.bits 
 & bit1)`. That doesn't work, however. I get an error message 
 saying "need 'this' for 'bits' of type 'int'". Is there a way 
 to make this work, or am I stuck with the uglier mixin at the 
 usage site?
i don't think that you can cheat like this. ;-) templates aren't macros, and `mixin` inside the template works immediately. i.e. it's trying to *execute* the mixined code in compile time. so your template with `mixin` in it tries to check `embedded.bits` in *compile* time, and then complains about missing 'this', as it should. i don't think that you can do c-like macros in D.
Hmm, I confused myself over when the expression is interpreted. I got it into my head that the template expansion would somehow delay interpretation of the expression so it could be picked up at runtime, but of course `enum` forces it to be CTFE'd.
Dec 24 2014
parent ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Wed, 24 Dec 2014 19:52:31 +0000
Meta via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

 Hmm, I confused myself over when the expression is interpreted. I=20
 got it into my head that the template expansion would somehow=20
 delay interpretation of the expression so it could be picked up=20
 at runtime, but of course `enum` forces it to be CTFE'd.
sometimes i want to have some kind of C-like macros in D too, which just inserts the generated string in the place of instantiation with implicit `mixin`. maybe someone will write a DIP/ER for this...
Dec 24 2014
prev sibling parent reply "Meta" <jared771 gmail.com> writes:
I am curious, however, why changing `enum` to `auto` (or bool) 
doesn't work. You said that the mixin tries to interpret the 
expression `cast(bool)(embeddedTest.bits & <enumName>)` at 
compile time, but I don't understand why that would be so when 
the storage is auto and not enum. I guess mixin doesn't work 
quite like I thought it did; it's not quite the equivalent of 
pasting the mixed-in code.
Dec 24 2014
parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 24 December 2014 at 20:08:07 UTC, Meta wrote:
 I am curious, however, why changing `enum` to `auto` (or bool) 
 doesn't work. You said that the mixin tries to interpret the 
 expression `cast(bool)(embeddedTest.bits & <enumName>)` at 
 compile time, but I don't understand why that would be so when 
 the storage is auto and not enum. I guess mixin doesn't work 
 quite like I thought it did; it's not quite the equivalent of 
 pasting the mixed-in code.
Ok, I understand now. I missed the fact that even when it's an auto or a bool variable, it is CTFE-initialized because it's outside the constructor. I'm so close, yet so far from making this work.
Dec 24 2014