digitalmars.D.learn - How do I iterate over enum members at runtime?
- Andrej Mitrovic (25/25) Apr 09 2011 E.g.:
- Jesse Phillips (21/30) Apr 09 2011 You have everything you need, just put them all together:
- Andrej Mitrovic (2/2) Apr 09 2011 What the.. I was sure mixin wouldn't work in a foreach loop.
- Jonathan M Davis (5/6) Apr 09 2011 Whyever not? mixins work in most places. I believe that the problem is t...
- Andrej Mitrovic (22/28) Apr 09 2011 Well in this case it works, but it's not always so easy. For example:
- Jesse Phillips (2/27) Apr 09 2011
- Cliff Hudson (4/38) Apr 09 2011 You could probably make a template out of the ugly __traits invocation a...
- Andrej Mitrovic (17/17) Apr 09 2011 Well, the C code I was translating had something like this:
- Jesse Phillips (3/5) Apr 09 2011 It has .max
- Andrej Mitrovic (14/19) Apr 09 2011 That doesn't show me the number of values an enum tag has, only its
- Dan Olson (11/41) Apr 10 2011 I'm exploring more and found there is also std.traits.EnumMembers. It's
- Andrej Mitrovic (2/10) Apr 11 2011 Nice find, thanks!
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
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
What the.. I was sure mixin wouldn't work in a foreach loop. Thanks, Jesse!
Apr 09 2011
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
On 4/10/11, Jonathan M Davis <jmdavisProg gmx.com> 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.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
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
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:thatWhat the.. I was sure mixin wouldn't work in a foreach loop.Whyever not? mixins work in most places. I believe that the problem isthey have to be a whole expression or statement rather than just a pieceofone, so sometimes you can't use a mixin for something small and have toputmore of the code in a mixin, but string mixins do work in most places. - Jonathan M DavisWell 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
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
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
On 4/10/11, Jesse Phillips <jessekphillips+D gmail.com> wrote:Andrej Mitrovic Wrote: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 }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
Jesse Phillips <jessekphillips+d gmail.com> writes:On Sat, 09 Apr 2011 16:20:06 -0400, Andrej Mitrovic 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 -- DanI 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 10 2011
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.lengthNice find, thanks!
Apr 11 2011