0

I often use enums for bitflags like the following

enum EventType {
    NODE_ADDED = 1 << 0,
    NODE_DELETED = 1 << 1,
    LINK_ADDED = 1 << 2,
    LINK_DELETED = 1 << 3,
    IN_PIN_ADDED = 1 << 4,
    IN_PIN_DELETED = 1 << 5,
    IN_PIN_CHANGE = 1 << 6,
    OUT_PIN_ADDED = 1 << 7,
    OUT_PIN_DELETED = 1 << 8,
    OUT_PIN_CHANGE = 1 << 9,

    ALL = NODE_ADDED | NODE_DELETED | ...,
};

Is there a clean less repetitive way to define an ALL flag that combines all other flags in an enum? For small enums the above works well, but lets say there are 30 flags in an enum, it gets tedious to do it this way. Does something work (in general) like this

ALL = -1

?

2 Answers2

3

Use something that'll always cover every other option, like:

ALL = 0xFFFFFFFF

Or as Swordfish commented, you can flip the bits of an unsigned integer literal:

ALL = ~0u

To answer your comment, you can explicitly tell the compiler what type you want your enum to have:

enum EventType : unsigned int
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • 2
    *`0xFFFFFFFF`* – `~0u` or `~0ul` or `~0ull`. Less to write, less to read, less error-prone. – Swordfish Dec 01 '18 at 16:03
  • @Swordfish Both are possible, I like this one better since it more clearly expresses intent for me, I guess that's personal though. Less to read isn't always better. – Hatted Rooster Dec 01 '18 at 16:04
  • But is there a way to let the compiler decide which size the enum should have? – Philipp Mildenberger Dec 01 '18 at 16:07
  • @PhilippMildenberger The standard says "The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration." so yeah. – Hatted Rooster Dec 01 '18 at 16:08
  • @SombreroChicken Your quote is the perfect reason to answer: So Nay. You control the size of the underlying type of the enum with using either `u`, `ul` or `ull` as suffix to the "match-all" bitmask. – Swordfish Dec 01 '18 at 16:11
  • Isn't it UB to cast a numeric value to an enum with underlying type that is not fixed, when the value is possibly out of range, as in `~0u`? – zett42 Dec 01 '18 at 16:11
  • @Swordfish So yeah as in "the compiler already decides for you". – Hatted Rooster Dec 01 '18 at 16:12
  • @SombreroChicken You get me wrong. With explicitly sepcifying the thype of the literal YOU tell the compiler which type. – Swordfish Dec 01 '18 at 16:12
  • @zett42 *Isn't it UB to cast a numeric value [...]* – No: [dcl.enum/7](http://eel.is/c++draft/dcl.enum#7) – Swordfish Dec 01 '18 at 16:14
  • 1
    @zett42 You are referring to unrelated things. There is no cast in `enum { foo = 42uul; };`. [dcl.enum/5.1 ff.](http://eel.is/c++draft/dcl.enum#5.1) – Swordfish Dec 01 '18 at 16:25
  • You are propably right because this isn't about casting to enum, but declaring an enum. – zett42 Dec 01 '18 at 16:25
1

The root problem here is how may one-bits you need. That depends on the number of enumerators previously. Trying to define ALL inside the enum makes that a case of circular logic

Instead, you have to define it outside the enum:

const auto ALL = (EventType) ~EventType{};

EventType{} has sufficient zeroes, ~ turns it into an integral type with enough ones, so you need another cast back to EventType

MSalters
  • 173,980
  • 10
  • 155
  • 350