Reputation: 65
If I have a function that returns based on switching over a enum class
, gcc emits warning: control reaches end of non-void function [-Wreturn-type]
. Example code:
enum class Test { a, b, c } ;
int foo(Test test) {
switch (test) {
case Test::a: return 0;
case Test::b: return 1;
case Test::c: return 2;
}
}
I have thought of two solutions but neither seem correct:
1) have a default case that throws. However, when I add an additional member to the enum class
I no longer receive an error that I missed a case.
2) Suppress the warning with a pragma, but then I don't guard against someone passing in a static_cast<Test>(123)
.
So my question is, how to deal with -Wreturn-type errors for switch over C++11 enum class?
Upvotes: 4
Views: 591
Reputation: 30020
Note: this answer is written with performance in mind (if you don't need it, just ignore this, and put some fatal error after the switch).
I'd recommend to use a compiler-specific feature to mark unreachable code. All major compilers have something like this. For example, GCC/Clang/icc has __builtin_unreachable
, MSVC has __assume(false)
.
Use these tools in release mode. In debug mode, put some fatal error (assert, exception, whatever) there. This way, while in development, you'll catch errors, and in release mode, generated code will be efficient.
Note, there is a proposal, which intends to add std::unreachable()
to C++. When this hopefully gets through, you can use it in such codes. Until then, you have to resort to the previously-mentioned compiler-specific solution.
Upvotes: 3
Reputation: 385405
Typically I will put something after the switch, be it a throw something()
or a return -1
. You need to ensure that, at runtime, a call to this function is at least safe no matter what happens. Your compiler is telling you as much.
Example:
enum class Test { a, b, c } ;
int foo(Test test) {
switch (test) {
case Test::a: return 0;
case Test::b: return 1;
case Test::c: return 2;
}
throw std::runtime_error("Unhandled Test enumerator " + std::to_string((int)test) + " in foo()");
}
Ideally your customers will never see this but, if they do (by means of your top-level catch
— you have one, right?), you know immediately what the problem is and can fix it.
Additionally (but not solely) I will consider putting a debug assertion like assert
(or project-specific equivalent) so that this bug is detected during development. (Though, in the example above with try
, that would actually prevent generation of the useful error message, so it's not always appropriate.)
Also if you turn on -Werror
then fail to add an item to the switch
, your project won't build anyway so that solves the problem at source (literally!).
In general, don't ignore or try to suppress warnings: heed them!
Upvotes: 3