Subtyping of an enum

Alex AJ at gmail.com
Mon Apr 15 14:20:57 UTC 2019


On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:
> Hello! I am currently trying to add a custom `toString` method 
> to an enum so that:
> 1. Enum members would still have numeric values and can be 
> easily compared (things like `enum a { foo = "FOO", bar = 
> "BAR”}` won't do, I want `a.foo < a.bar)`)
> 2. More custom methods can be implemented in the future
>
> Obvious solution is to wrap an enum in a structure and utilize 
> 'alias this' for subtyping like this:
> ```
> struct Enum {
>   private {
>     enum internal {
>       foo,
>       bar
>     }
>     internal m_enum;
>   }
>   this(internal i) { m_enum = i; }
>   alias m_enum this;
>   string toString() {
>     // custom implementation of toString
>   }
> }
> ```
>
> This seems to work just fine for assigning and comparisons but 
> passing Enum as a function argument does not work:
> ```
> void fun(Enum e) {}
>
> fun(Enum.foo);
> ---
> Error: function fun(Enum e) is not callable using argument 
> types (internal)
> Cannot pass argument foo of type internal to parameter Enum e.
> ```
>
> Of course, I could just define a bunch of functions that accept 
> my enum as the first argument and call them using UFCS but it'd 
> require to explicitly specify functions instead of D taking 
> care of that (toString() for structures is called automagically 
> by functions like writeln) and those functions would hang 
> around here and there totally unorganized. I prefer to keep 
> functions inside of structures and classes.
>
> If there are other ways of achieving the same *and* keeping 
> code clean and organized, please share.
>
> Thank you in advance,
> Anton.

yes,

import std.stdio, std.meta, std.traits, std.conv;

enum _MyEnum : int { a,b,c}

struct _Enum(T)
{
    T value;
    alias value this;
    // generate static field members
    static foreach(e, v; EnumMembers!T)
    {
      pragma(msg, "static MyEnum "~to!string(v)~" = 
MyEnum(T."~to!string(v)~");");
      mixin("static MyEnum "~to!string(v)~" = 
cast(MyEnum)(T."~to!string(v)~");");
    }
}

alias _Enum!_MyEnum MyEnum;

void foo(MyEnum e)
{
    writeln(to!int(e));
}
void main()
{
     foo(MyEnum.a);
     foo(MyEnum.b);
     foo(MyEnum.c);
}

https://run.dlang.io/is/WOcLrZ

Note that value is never used, it just makes the cast work and 
treats the struct as an enum. Not sure if there is a way around 
that.







More information about the Digitalmars-d-learn mailing list