Why does MSVC warn that "not all control path returns a value" with enum class ?

Started by
13 comments, last by Aldacron 8 years, 3 months ago

for MSVC, use __assume(0) to hint the compiler you know what you're doing.

Advertisement

is perfectly fine and constexpr, even though one compiler may assign 0 to foo and another one -1 and yet another one 4 (most probably all will assign 4).

I think constexpr isn't really the issue. It's fine for one compiler to assign 0 and another to assign -1. Indeed, I think that "makes no sense" is certainly a perfectly good constant expression, no matter what its value may be (as long as the value doesn't change during the lifetime of the program). Note that it is also perfectly fine to do any of these:


enum class TrafficLight{ red = 1, yellow = 2, green = 4 }; // assumes you are neither in UK nor Germany where there is red-yellow too
enum class AlertCondition { none = 0, yellow = 1, red = 2 };

AlertCondition enterprise_status = static_cast<AlertCondition>(TrafficLight::red);             // WTF?

TrafficLight elm_street = static_cast<TrafficLight>(3);                                        // WTF?
TrafficLight main_street = static_cast<TrafficLight>(TrafficLight::red + TrafficLight::green); // WTF?
TrafficLight second_street = static_cast<TrafficLight>(0);                                     // Does that mean it's turned off?


Thing is, it is entirely meaningless to do any of the above. Assigning a red traffic light to an alert condition will generate a yellow alert (since the value fits within the range, so the value is preserved). That was the primary example of the reasoning behind strongly typed enums being added (which are a blessing and a curse, since -- why, just why? -- you cannot using them in a function as you could if you wrapped an anonymous enum in a namespace, and neither can the compiler figure out from a function's signature that only one is possible, so you always have to repeatedly type out the fully qualified name when you shouldn't have to).

But also, it is possible, and legitimate, to have red and green on a traffic light at the same time (and indeed this rarely, very rarely happens in real life -- for several decades, traffic lights in Germany were not allowed to be operated by computer systems for exactly that reason, although the technology was readily available -- they were strictly mechanical with forcible control, mutually exclusive switches). Depending on whether you follow the "underlying type" or the "otherwise" clause in the two contradicting paragraphs of the standard, this will or will not preserve the numeric value. But in any case, the numeric value has no meaning, so that is inconsequential.

It just doesn't make sense to do certain things. Because of that, however, if your program allows for that to happen, it is perfectly harmless if the value that you get is arbitrary. There is no difference between any arbitrary "doesn't make sense" and any other "doesn't make sense".

If, however, such a thing can be detected at compile time, it is immensely helpful if the compiler warns you about it, because you are almost certainly making a gigantic stupid mistake. Insofar, I deem this warning very valuable.

is perfectly fine and constexpr, even though one compiler may assign 0 to foo and another one -1 and yet another one 4 (most probably all will assign 4).

I think constexpr isn't really the issue. It's fine for one compiler to assign 0 and another to assign -1. Indeed, I think that "makes no sense" is certainly a perfectly good constant expression, no matter what its value may be (as long as the value doesn't change during the lifetime of the program).

Thinking a bit more about the problem, constexpr evaluation still differs from compiler to compiler (i.e. for floating point), so this is in fact a no-issue.

I agree with everything you have said (except that TrafficLight::red + TrafficLight::green does not compile because there is no operator+ and enum class is not implicitely convertible to its underlying numerical type).

IMHO just add a default case to switches, it may come in handy at some point in the future and catch some errors. No harm in doing that.

Doesn't MSVC have a compiler flag to turn this warning off?

Doesn't MSVC have a compiler flag to turn this warning off?

You can turn on all compiler warnings off using pragma push pop. It doesn't mean it's a good solution though.

Is there some way to detect at build time if all enums are present in all switch statement of a code base with MSVC then ? Adding a default case will only fails at runtime and I don't see any "type" that can hold only symbolic value by making the actual binary representation innaccessible.

In D, you can use a final switch with an enum. This will cause the compiler to error out if you don't have a case for every member and won't let you use runtime-initialized values. It's very handy. It would be great to see something like that in C++.

This topic is closed to new replies.

Advertisement