strong enums: why implicit conversion to basetype?

Era Scarecrow rtcvb32 at yahoo.com
Sun Jan 29 17:07:24 PST 2012


> > ///T of type ENUM, and S of an integral.
> > struct HandleFlags(T, S)
> >  {
> >     S state;    ///Holds
> state.
> >     alias T T_Enum;
> >
> >      this(T[] setFlags...);
> >
> >     ///Returns true/false if a specific
> ENUM flag has been set.
> >     bool check(T[] flag...);
> >
> >     ///Returns true/false if all flags are set
> ENUM flag has been set.
> >     bool checkAll(T[] flag...);
> >     
> >     /**
> >     Checks if a flag has been set,
> returning that ENUM, otherwise returning  
> > the Else flag.
> >     */
> >     T checkElse(T Else, T[] flag...);
> >
> >     ///Sets specific flag(s) on
> >     void setFlag(T[] flag...);
> >
> >     ///turns listed flags off.
> >     void clearFlag(T[] flag...);
> >
> >     ///reverses the state of a specific
> flag.
> >     void flipFlag(T[] flag...);
> > }
> 
> Is it possible to 'auto-detect' the integral type? I makes
> little sense to use a signed type or a type too small for the enum for
> example.

Yes, I suppose it could auto detect it, however having it the smallest size possible isn't the right answer. If you begin using enums for your flags and you are accessing C code that uses it's enums, it may only use 10 bits but uses a 32bit value. Hopefully by having only one data member (of your int type) you can safely forcibly cast it (If it's the same size)

> And in the same fashion: Do you map an enum value to "1 << enum_value" in the bit field? I know that in Delphi 'sets' worked great for me and so I am biased for everything that works the same way. It is also the most  natural way to work with enums that can be represented as a bit field IMO.  

 Current implementation you are explicit (ie 0x1000); Wouldn't be hard to use a mixin function to do the work for you.

> This means that enum values cannot be larger than 63 of course (so they fit inside a ulong).
> What else? hmm? I'm wondering if the documentation for flipFlag should be "reverses the state of all given flags".

 Correct. So if flag A was set and B wasn't, and you flip both, B is set and A isn't. I'm using variadic functions since if you know you are doing multiple flags you shouldn't be required to make x calls when you don't need to.

> How is checkElse supposed to work. I could imagine the function of a  
> method with the signature "T (T flag, T else)". What is the use case for it? Even check seems to accept multiple flags, where I would expect only one.

I've updated the signature to use "const T checkElse(T Else, T flag...)". Now how you would use this is if you want an ENUM flag returned and not a true/false, but you don't want to have to manually check. so you can do this. (Returns first true ENUM, or if it fails return Else)

HandleFlags!(E, int) Flags;

somefunc(Flags.checkElse(ETEST.unused, ETEST.isMaster, ETEST.isSlave), ...)

Rather than..
if (Flags.check(TEST.isMaster))
    somefunc(ETEST.isMaster, ...)
else if (Flags.check(TEST.isSlave))
    somefunc(ETEST.isSlave, ...)
else
    somefunc(ETEST.unused, ...)

> We could also introduce some operator overloading: setFlag
> <=> +=,  
> clearFlag <=> -=, flipFlag <=> ^=, check
> <=> in. (setFlag could be |= as  
> well, but += is more consistent with clearFlag as -=)

 Yep, overloading would be useful later :) But not just yet.



More information about the Digitalmars-d mailing list