1

While searching for an answer to the question above, I came across the answer of Luke Kowald to the question Check if a value is defined in an C enum?. It states that one can check if a value is a valid for an enum, by checking if it is equal to one of the possible values in a switch.

typedef enum {
    MODE_A,
    MODE_B,
    MODE_C
}MODE;

int modeValid(int mode)
{
    int valid = 0;

    switch(mode) {
        case MODE_A:
        case MODE_B:
        case MODE_C:
            valid = 1;
    };

    return valid;
}

Suppose, the value int mode has been converted to type MODE prior to checking if it is valid:

int modeValid(MODE mode)
{
    int valid = 0;

    switch(mode) {
        case MODE_A:
        case MODE_B:
        case MODE_C:
            valid = 1;
    };

    return valid;
}

Would this still be guaranteed to work or could the compiler optimize the check into always true as the enum should never have a value other than the ones checked for?

How would this behave in case of enum classes?

Paul R.
  • 678
  • 5
  • 19
  • 2
    Do not tag both C and C++ except when asking about differences or interactions between the changes. This is especially important for language-lawyer questions, as the standards increasingly diverge, meaning the answers will be different for the two **different** languages and there will be confusion about answering. Pick one language and delete the other tag. If you want to ask about both languages, enter a separate question for the other. – Eric Postpischil Jun 24 '21 at 15:01
  • 3
    an enums range is determined by the underlying type, not by the values you give a name to – 463035818_is_not_an_ai Jun 24 '21 at 15:02
  • 2
    `typedef enum` is not a C++ way. Using 0 and 1 as bool is not a C++ way. – 273K Jun 24 '21 at 15:07
  • Does this answer your question? [How to check if enum value is valid?](https://stackoverflow.com/questions/4969233/how-to-check-if-enum-value-is-valid) – Brian61354270 Jun 24 '21 at 15:07
  • I am well aware of C and C++ being to different languages. Since my concrete problem is in C++ (at an interface to C code) I chose C++ for this question. – Paul R. Jun 24 '21 at 15:08
  • @S.M. You are right. It is, however , a citation I came accross. – Paul R. Jun 24 '21 at 15:08
  • @S.M. all of these are valid C++, but enum classes (which the question asks about) are not C. – Aykhan Hagverdili Jun 24 '21 at 15:22
  • @AyxanHaqverdili Have I used the word "invalid" somewhere? – 273K Jun 24 '21 at 15:58
  • @S.M. you removed the `C++` tag, leaving just the `C` tag. The question asks about `enum class` which is C++. Hence the comment. – Aykhan Hagverdili Jun 24 '21 at 16:51

3 Answers3

3

C++ 2018 draft N4659 10.2 (“Enumeration declarations,” [dcl.enum]) 8 tells us what the values of an enumeration type are. I will quote it below, but it essentially says:

  • If an enumeration has an underlying type that is fixed, the values of the enumeration are the values of the underlying type. So there can be (integer) values in that type that are not values of the enumerators (the named values).
  • If the underlying type is not fixed, the values of the enumeration are essentially those of a bit-field with enough bits to represent the named values. Again, this may result in there being more (integer) values in the enumeration type than there are named enumerators.

The paragraph explicitly states “It is possible to define an enumeration that has values not defined by any of its enumerators.”

Therefore, unless the named enumerators fill the range of the enumeration type, it is possible for your mode object of type MODE to have a value that is not one of the named enumerator values of the MODE type. Converting a value to the MODE type will not ensure the result has the value of one of the named enumerators.

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, for an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for a two’s complement representation and 0 for a ones’ complement or sign-magnitude representation. bmax is the smallest value greater than or equal to max(|emin| − K, |emax|) and equal to 2M − 1, where M is a non-negative integer. bmin is zero if emin is non-negative and −(bmax + K) otherwise. The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M, 1) if bmin is zero and M + 1 otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators. If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
3

Would this still be guaranteed to work

Yes.

No rule disallows calling the function like this:

modeValid(static_cast<MODE>(42));

And because that won't match any of the case labels, the behaviour must be that 0 is returned.

could the compiler optimize the check into always true as the enum should never have a value other than the ones checked for?

The as-if rule applies. If the compiler can prove that observed behaviour is as specified, then yes. This can be the case for example when the function call is expanded inline with a compile time constant argument.

How would this behave in case of enum classes?

Same.


Standard rules (from latest C++ draft):

The values of an enum are the values of the underlying type:

[dcl.enum]

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, the values of the enumeration are the values representable by a hypothetical integer type with minimal width M such that all enumerators can be represented. ...

The underlying type is an integral type:

[dcl.enum]

Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be fixed. ...

eerorika
  • 232,697
  • 12
  • 197
  • 326
3

While enum has named values, it can also hold all other values of the underlying type. Same applies to enum class. This is perfectly legal:

enum Color { red = 0xFF0000, green = 0x00FF00, blue = 0x0000FF };

int main() {
  Color buttonColor = static_cast<Color>(red | green);  // yellow
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93