January 30, 2012 Re: strong enums: why implicit conversion to basetype? | ||||
|---|---|---|---|---|
| ||||
> > ///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. | ||||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply