In general, enum
s are not exclusive. Someone could call your function like useType( (type_t)3 );
for example. This is mentioned specifically in C++14 [dcl.enum]/8:
It is possible to define an enumeration that has values not defined by any of its enumerators.
Now, there are a bunch of rules about exactly which other values are possible for which other sorts of enum.
There are two categories of enum. The first is fixed underlying type, e.g. enum type_t : int
, or enum class type_t
. In those cases all values of the underlying type are valid enumerators.
The second is not fixed underlying type, which includes pre-C++11 enums such as yours. In this case the rule about values can be summarized by saying: compute the smallest number of bits necessary in order to store all values of the enum; then any number expressible in that number of bits is a valid value.
So - in your specific case, a single bit can hold both values A
and B
, so 3
is not valid value for the enumerator.
But if your enum were A,B,C
, then even though 3
is not listed specifically, it is a valid value by the above rule. (So we can see that almost all enums will not be exclusive).
Now we need to look at the rule for what happens if someone does actually try to convert 3
to type_t
. The conversion rule is C++14 [expr.static.cast]/10, which says that an unspecified value is produced.
However, CWG issue 1766 recognized that the C++14 text was defective and has replaced it with the following:
A value of integral or enumeration type can be explicitly converted to a complete enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the behavior is undefined.
Therefore, in your specific case of exactly two enumerators with value 0
and 1
, no other value is possible unless the program has already triggered undefined behaviour, so the warning could be considered a false positive.
To remove the warning, add a default:
case that does something. I'd also suggest, in the interest of defensive programming, that it's a good idea to have a default case anyway. In practice it may serve to 'contain' the undefined behaviour: if someone does happen to pass an invalid value then you can throw or abort cleanly.
NB: Regarding the warning itself: it's impossible for a compiler to accurately warn if and only if control flow would reach the end of a function , because this would require solving the halting problem.
They tend to err on the side of caution: the compiler will warn if it is not completely sure, meaning that there are false positives.
So the presence of this warning does not necessarily indicate that the executable would actually allow entry into the default path.
default:
with your preferred assert mechanism. – Chromato