On GCC 7 I have enabled most of all warnings on Qt creator 4.9. Now I have a switch statement which covers all enumeration values. If I add a default:
I get a warning (from Qt creator):
warning: default label in switch which covers all enumeration values
If I remove the default:
I get another warning (from GCC):
error: this statement may fall through [-Werror=implicit-fallthrough=]
}
^
error: all warnings being treated as errors
What am I supposed to do? Turn off warnings? They are useful, I don't want to turn off any of them, but Wimplicit-fallthrough
seems to be faulty.
[[fallthrough]]
doesn't help because the case
s end with a return
thus I get (from Qt creator):
warning: fallthrough annotation in unreachable code
__attribute__ ((fallthrough))
didn't do anything either. Neither did /* FALLTHRU */
or [[gnu::fallthrough]]
or // fall through
. Presumably because of -pedantic
?
Example:
enum class E {a, b, c};
QVariant fun(E e) {
switch (e) {
case E::a: return "something";
case E::b: return "something_else";
case E::c: return "something_different";
// default: return QVariant{};
// Do I add a default:? What do I add here?
}
}
Hopefully the things I've tried shows that my question is not a duplicate of this or this or other similar questions because they don't solve my problem.
Consider fun(static_cast<E>(42))
. This is a perfectly well-defined conversion, but the function from your question will reach the end without returning, and your program's behavior will be undefined. That's why GCC warns that control may reach the end of a non-void function.
So why not add a default
case? Consider what happens if someone goes back and adds another constant to E
, but forgets to update fun
. Without a default
, GCC will helpfully warn you that the switch doesn't handle all of E
's constants. If you add a default
case, you've defeated that very helpful protection.
So what's the Right ThingTM to do? Return your default value (or throw
or call abort()
to crash, as appropriate) at the end of the function, after the switch
:
enum class E {a, b, c};
QVariant fun(E e) {
switch (e) {
case E::a: return "something";
case E::b: return "something_else";
case E::c: return "something_different";
}
return "some_default"; // or throw or abort()
}
This gives you the best of both worlds. If someone passes a value that isn't one of the pre-defined enumerator constants, it will behave in a well-defined way. If someone adds a new constant to E
and forgets to update fun
then the compiler will still issue a warning.
For further discussion, Jason Turner covered this topic (among others) in his CppCon 2018 talk, which is worth a watch.
If my first answer doesn't satisfy, this perhaps this will. This is how I resolved the issue locally:
QVariant fun(E e) {
switch (e) {
case a: return "something";
case b: return "something_else";
case c: return "something_different";
}
return "";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With