www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How do I iterate over enum members at runtime?

reply Andrej Mitrovic <none none.none> writes:
E.g.:

enum Metrics : int 
{
	SM_CXSCREEN = 0,
	SM_CYSCREEN,
	SM_CXVSCROLL,
	SM_CYHSCROLL,
	SM_CYCAPTION,
	SM_CXBORDER,
}

void foo(int m)
{
}

void main()
{
    foreach (m; Metrics)
    {
        foo(m);
    }
}

This won't work.

I know there's traits to get strings at compile time, e.g.:
auto b = [ __traits(allMembers, Metrics) ];

but this doesn't help me try out those enum values at runtime. It could almost
work if I could use a mixin() in a foreach loop, but that's lucid dreaming.

Another alternative might be to create an array out of the enum, but I don't
know of any way of doing this.
Apr 09 2011
next sibling parent reply Jesse Phillips <jessekphillips+d gmail.com> writes:
On Sat, 09 Apr 2011 16:20:06 -0400, Andrej Mitrovic wrote:

 I know there's traits to get strings at compile time, e.g.: auto b = [
 __traits(allMembers, Metrics) ];
 
 but this doesn't help me try out those enum values at runtime. It could
 almost work if I could use a mixin() in a foreach loop, but that's lucid
 dreaming.
 
 Another alternative might be to create an array out of the enum, but I
 don't know of any way of doing this.

You have everything you need, just put them all together: enum Metrics : int { SM_CXSCREEN = 0, SM_CYSCREEN, SM_CXVSCROLL, SM_CYHSCROLL, SM_CYCAPTION, SM_CXBORDER, } void foo(int m) { } void main() { foreach (m; __traits(allMembers, Metrics)) { foo(mixin("Metrics." ~ m)); } }
Apr 09 2011
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 What the.. I was sure mixin wouldn't work in a foreach loop.

Whyever not? mixins work in most places. I believe that the problem is that they have to be a whole expression or statement rather than just a piece of one, so sometimes you can't use a mixin for something small and have to put more of the code in a mixin, but string mixins do work in most places. - Jonathan M Davis
Apr 09 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/10/11, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 What the.. I was sure mixin wouldn't work in a foreach loop.

Whyever not? mixins work in most places. I believe that the problem is that they have to be a whole expression or statement rather than just a piece of one, so sometimes you can't use a mixin for something small and have to put more of the code in a mixin, but string mixins do work in most places. - Jonathan M Davis

Well in this case it works, but it's not always so easy. For example: import std.conv; enum Metrics : int { val0, val1, val2 } void foo(int m) { } void main() { foreach (index; 0..3) { foo(mixin("Metrics.val" ~ to!string(index))); } } So even though you might think "hey, it's obvious index in this case can never be anything other than 0, 1, or 2", you still won't be able to compile this. CTFE is a tricky thing.
Apr 09 2011
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
You must iterate a compile time only construct.  So yes it would be nice to be
able to say: static foreach and have the compiler tell you, no I can't do that
(and force it if it can).

Andrej Mitrovic Wrote:

 Well in this case it works, but it's not always so easy. For example:
 
 import std.conv;
 enum Metrics : int
 {
     val0,
     val1,
     val2
 }
 
 void foo(int m)
 {
 }
 
 void main()
 {
    foreach (index; 0..3)
    {
        foo(mixin("Metrics.val" ~ to!string(index)));
    }
 }
 
 So even though you might think "hey, it's obvious index in this case
 can never be anything other than 0, 1, or 2", you still won't be able
 to compile this. CTFE is a tricky thing.

Apr 09 2011
prev sibling next sibling parent Cliff Hudson <cliff.s.hudson gmail.com> writes:
--0016e6d9765123358304a084338a
Content-Type: text/plain; charset=ISO-8859-1

You could probably make a template out of the ugly __traits invocation as
well?

On Sat, Apr 9, 2011 at 3:37 PM, Andrej Mitrovic
<andrej.mitrovich gmail.com>wrote:

 On 4/10/11, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 What the.. I was sure mixin wouldn't work in a foreach loop.

Whyever not? mixins work in most places. I believe that the problem is

 they have to be a whole expression or statement rather than just a piece

 one, so sometimes you can't use a mixin for something small and have to

 more of the code in a mixin, but string mixins do work in most places.

 - Jonathan M Davis

Well in this case it works, but it's not always so easy. For example: import std.conv; enum Metrics : int { val0, val1, val2 } void foo(int m) { } void main() { foreach (index; 0..3) { foo(mixin("Metrics.val" ~ to!string(index))); } } So even though you might think "hey, it's obvious index in this case can never be anything other than 0, 1, or 2", you still won't be able to compile this. CTFE is a tricky thing.

--0016e6d9765123358304a084338a Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable You could probably make a template out of the ugly __traits invocation as w= ell?=A0<br><br><div class=3D"gmail_quote">On Sat, Apr 9, 2011 at 3:37 PM, A= ndrej Mitrovic <span dir=3D"ltr">&lt;<a href=3D"mailto:andrej.mitrovich gma= il.com">andrej.mitrovich gmail.com</a>&gt;</span> wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex;"><div><div></div><div class=3D"h5">On 4/10/1= 1, Jonathan M Davis &lt;<a href=3D"mailto:jmdavisProg gmx.com">jmdavisProg = gmx.com</a>&gt; wrote:<br> &gt;&gt; What the.. I was sure mixin wouldn&#39;t work in a foreach loop.<b= r> &gt;<br> &gt; Whyever not? mixins work in most places. I believe that the problem is= that<br> &gt; they have to be a whole expression or statement rather than just a pie= ce of<br> &gt; one, so sometimes you can&#39;t use a mixin for something small and ha= ve to put<br> &gt; more of the code in a mixin, but string mixins do work in most places.= <br> &gt;<br> &gt; - Jonathan M Davis<br> &gt;<br> <br> </div></div>Well in this case it works, but it&#39;s not always so easy. Fo= r example:<br> <br> import std.conv;<br> enum Metrics : int<br> {<br> =A0 =A0val0,<br> =A0 =A0val1,<br> =A0 =A0val2<br> <div class=3D"im">}<br> <br> void foo(int m)<br> {<br> }<br> <br> void main()<br> {<br> </div> =A0 foreach (index; 0..3)<br> =A0 {<br> =A0 =A0 =A0 foo(mixin(&quot;Metrics.val&quot; ~ to!string(index)));<br> =A0 }<br> }<br> <br> So even though you might think &quot;hey, it&#39;s obvious index in this ca= se<br> can never be anything other than 0, 1, or 2&quot;, you still won&#39;t be a= ble<br> to compile this. CTFE is a tricky thing.<br> </blockquote></div><br> --0016e6d9765123358304a084338a--
Apr 09 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Well, the C code I was translating had something like this:
struct SysMetrics
{
    int iIndex;
    char* szLabel;
    char* szDesc;
}

And then it used an array of these structures. So for all existing
enums that started with "SM_", those fields were populated with the
enum value and a name and description. A 200 line header file was
filled by hand. I really hope the author had some help from an editor
for that, lol!.

I've managed to do the same in about a dozen lines of code, although I
didn't fill the description field (I don't need it anyway):
http://codepad.org/EJEuc6qA

It's a shame that an enum with a tag doesn't have a .length property.
I've had to use __traits to build an array just to get the length.
Apr 09 2011
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Andrej Mitrovic Wrote:

 It's a shame that an enum with a tag doesn't have a .length property.
 I've had to use __traits to build an array just to get the length.

It has .max http://www.digitalmars.com/d/2.0/enum.html
Apr 09 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/10/11, Jesse Phillips <jessekphillips+D gmail.com> wrote:
 Andrej Mitrovic Wrote:

 It's a shame that an enum with a tag doesn't have a .length property.
 I've had to use __traits to build an array just to get the length.

It has .max http://www.digitalmars.com/d/2.0/enum.html

That doesn't show me the number of values an enum tag has, only its largest value. void main() { writeln(foo.max); // 101, not 4 } enum foo : int { a, b, c = 100, d }
Apr 09 2011
prev sibling next sibling parent Dan Olson <zans.is.for.cans yahoo.com> writes:
Jesse Phillips <jessekphillips+d gmail.com> writes:

 On Sat, 09 Apr 2011 16:20:06 -0400, Andrej Mitrovic wrote:

 I know there's traits to get strings at compile time, e.g.: auto b = [
 __traits(allMembers, Metrics) ];
 
 but this doesn't help me try out those enum values at runtime. It could
 almost work if I could use a mixin() in a foreach loop, but that's lucid
 dreaming.
 
 Another alternative might be to create an array out of the enum, but I
 don't know of any way of doing this.

You have everything you need, just put them all together: enum Metrics : int { SM_CXSCREEN = 0, SM_CYSCREEN, SM_CXVSCROLL, SM_CYHSCROLL, SM_CYCAPTION, SM_CXBORDER, } void foo(int m) { } void main() { foreach (m; __traits(allMembers, Metrics)) { foo(mixin("Metrics." ~ m)); } }

I'm exploring more and found there is also std.traits.EnumMembers. It's a little simpler: foreach (m; EnumMembers!Metrics)) { foo(m); } And for number of members in enum Metrics EnumMembers!Metrics.length -- Dan
Apr 10 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/11/11, Dan Olson <zans.is.for.cans yahoo.com> wrote:
 I'm exploring more and found there is also std.traits.EnumMembers.  It's
 a little simpler:

     foreach (m; EnumMembers!Metrics))
     {
         foo(m);
     }

 And for number of members in enum Metrics

     EnumMembers!Metrics.length

Nice find, thanks!
Apr 11 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
What the.. I was sure mixin wouldn't work in a foreach loop.

Thanks, Jesse!
Apr 09 2011