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 cases 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