Reputation: 63720
enum ENUM(Option1,Option2,Option3);
string func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
}
}
This compiles and works but gives a compiler warning that not all control paths return. However isn't the point that if you use enums properly, this isn't the case? If another ENUM val is added, I want compilation to fail but as long as all cases are covered I want it to compile warning-free.
Is this the compiler protecting against bad casted values, is it just part of C++ and needs to be lived with?
Upvotes: 6
Views: 7030
Reputation: 299800
In C++, enums are not safe. You cannot expect an enum value to be one of the values defined in the enum declaration:
static_cast
from a int
Therefore, the compiler cannot expect the switch to return, even if you cover all elements of your enum. However, it is truly an error condition, functionally speaking.
There are two ways to react:
default
case to your enum
In order to choose wisely, remember that the compiler may (if you ask it) trigger a warning whenever a switch
does not cover all the cases of an enum
, at the condition that there is no default
statement. Smart compilers (ie Clang) allow to map warnings to errors individually, which greatly help catching those bugs.
Therefore, you have a decision to take:
default
default
Finally, you have to decide how to react, noting that using a runtime error is inconsistent with using a default statement (it's best to catch errors at compile-time whenever possible):
My personal fav is a UNREACHABLE(Text_)
macro, which provokes a memory dump in Debug (so that I get a full trace) and log an error and throw in Release (so that the server stops processing this request, but does not stop responding altogether).
This gives code like such:
char const* func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
}
UNREACHABLE("func(ENUM)")
}
Upvotes: 11
Reputation: 13854
What happens if for some reason x
is neither Option1
, nor Option2
, nor Option3
?
Sure, you could argue that will never happen, but since the method has to return something, you have two options:
add a return string("");
at the end.
add a default
to the switch
that returns string("")
.
As CodeGray points out, the second option is arguably better style. You could also return something other than an empty string.
Upvotes: 2
Reputation: 26094
From the compilers point of view, the type of the enum is an integer, so it's still possible that the value of x
is one of the other cases.
Normally, I would add a default:
label that triggers an internal error.
Hint: If you wrap the call the the intern error in an infinite loop, you don't have to invent a bogus return value. For example:
#define IntErr(x) for(;;) { InternalError(x); }
string func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
default: IntErr("Unexpected ENUM value");
}
}
Upvotes: 6