1

Given an enum like:

enum Colours { RED, YELLOW, BLUE, NUM_COLOURS };

And some logic like:

switch (colour) {
case RED: /* ... */ break;
case YELLOW: /* ... */ break;
case BLUE: /* ... */ break;
}

Most compilers with reasonable settings are going to protest that NUM_COLOURS is an unhandled case. However, that's obviously not how that particular value is meant to be used, and a case statement for it would be nonsense.

Is there any way to let the linter/compiler know that ignoring that specific value is correct and proper? Or a way of determining that value without including it in the enum?

sh1
  • 4,324
  • 17
  • 30
  • you have a default case that can do noting it should solve your issue https://en.cppreference.com/w/cpp/language/switch – alon Jul 18 '19 at 06:33
  • @alon except that's as good as compiling with `-Wall`, and you'll get no warning if you really forget a case - wouldn't recommend – Arne Jul 18 '19 at 06:37
  • how about using separate variable for your needs of NUM_COLOURS? like bool may work with a combination of the rest of enum – Andrey Lyubimov Jul 18 '19 at 06:38
  • 2
    Personally I'll just compile with the warning off and add a `static_assert(NUM_COLOURS == 3)` to catch modifications. – StoryTeller - Unslander Monica Jul 18 '19 at 06:38
  • 1
    Why can't you just do `case NUM_COLOURS: static_assert(NUM_COLOURS == 3); break;` ? – Jesper Juhl Jul 18 '19 at 06:38
  • 1
    I recommend looking at one of my questions, indication that compilers don't support [[maybe_unused]], was recently fixed in Clang: https://stackoverflow.com/questions/48488635/maybe-unused-on-enumerator – JVApen Jul 18 '19 at 06:43
  • 1
    `enum Colours { RED, YELLOW, BLUE }; enum { NUM_COLOURS = BLUE + 1 };` – melpomene Jul 18 '19 at 06:52

2 Answers2

1

The standard complaint way of doing this is with [[maybe_unused]]. You can add it after the enumeration value:

enum A
{
    B,
   C [[maybe_unused]]
};

void f(A a)
{
    switch (a)
    {
        case B: break;
    }
}

Unfortunately, compiler support for this ain't good. Clang recently resolved a bug to support this, must be in the upcoming 9.0.0 release (expected in September). (https://bugs.llvm.org/show_bug.cgi?id=36231) GCC and MSVC didn't support it half a year ago, as I don't need those, never logged a bug on that.

If you want support in other compilers/linters, you'll most likely have to log a bug for that. Given the size of the patch in Clang, I don't expect it to bee too much effort to support this in other tools.

JVApen
  • 11,008
  • 5
  • 31
  • 67
0

@JVApen's answer is, I think, the ideal answer that I was looking for. It's just a shame it doesn't sound like it's widely implemented.

In the interim, I realised that since I'm already using X-Macros to build stringified names for my enums, I can use the same technique to count the number of values, so the count does not appear as a part of the enum type:

#define LIST_OF_COLOURS(X) \
    X(RED) \
    X(GREEN) \
    X(BLUE)

#define LIST_OF_FRUIT(X) \
    X(APPLE) \
    X(ORANGE) \
    X(TOMATO)

#define X_LIST(x) x,
#define X_STRING_LIST(x) #x,
#define X_COUNT(x) +1
#define COMPREHENSIVE_SETUP(n, l)  \
    enum n { l(X_LIST) };  \
    char const* n##Names[] = { l(X_STRING_LIST) };  \
    enum { n##Count = 0 l(X_COUNT) };

COMPREHENSIVE_SETUP(Colour, LIST_OF_COLOURS)
COMPREHENSIVE_SETUP(Fruit, LIST_OF_FRUIT)

The trick being the last line of the COMPREHENSIVE_SETUP macro.

With that I can have ColourCount and FruitCount constants in place of NUM_COLOURS, and they're not a part of the enum so they don't need to appear in the switch.

sh1
  • 4,324
  • 17
  • 30