Using simple enumerators in D

85 Views Asked by At

Say I have the following enum:

struct Test {
    string value;
}

Test new_test(string value) {
    Test t;
    t.value = value;
    return t;
}

enum Foo : Test {
    A = new_test("a"),
    B = new_test("b"),
    c = new_test("c"),
}

I'm confused as to a few things. How do I pass this around to functions?

void do_something(Foo f) {

}
do_something(Foo.A);

// or

void do_something(Test t) {

}
do_something(Foo.A);

And finally, is there any way I can get the numerical value of the enum for example

A -> 0
B -> 1
C -> 2

Something simple like:

Foo.A.id ???
2

There are 2 best solutions below

0
BioTronic On BEST ANSWER

When you write

 enum Foo {
     A = new_test("a"),
     B = new_test("b"),
     C = new_test("c"),
 }

You're basically creating a named set of values. They have no numerical value, the way you think - they're just regular structs. If you need to know the index of a value in the set (such that getIndex(Foo.C) would return 2), you could use this code:

// Gets the index of an enum value in the enum it's part of.
int getIndex(T)(T value) if (is(T == enum)) {
    // Iterate over all the members of the enum, and return the index if it's a match.
    static foreach (i, member; __traits(allMembers, T)) {
        if (value == __traits(getMember, T, member))
            return i;
    }
    return -1;
}

As for passing it around, either way works, as you may have noticed. Again, there's nothing magical about enums. They're not a number disguised as a Test, and can be used like a Test in every way.

0
Qurashi On

I don't know why are you defining Foo as a Test here, you can just have an anonymous enum like:

enum Foo {
  a,
  b,
  c, 
}

or define it as a string:

enum Foo {
  A="a",
  B="b",
  C="c", 
}

in any case, it depends on your function design, if the function should receive only Foo then you should on pass a Foo and the same with Test, if the function you are writing should work with all Test objects not only these 3 predefined Tests then passing a Test will be your choice, however, if you want the function to work only with the enum you defined then use Foo, you get the point.

Regarding the id let's say you can have Test to contain another field called id and you initialize that with a number, now you can use that field as an identifier:

struct Test {
    string value;
    int id;
}

Test new_test(string value, int id) {
    Test t;
    t.value = value;
    t.id = id;
    return t;
}

enum Foo : Test {
    A = new_test("a", 1),
    B = new_test("b", 2),
    c = new_test("c", 3),
}

now if you want to get the index of one Foo you can use traits:

auto i = [__traits(allMembers, Foo)].countUntil(Foo.B.to!string);