switch may fall through (no it may not)

核能气质少年 提交于 2020-02-23 16:26:49

问题


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 them 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 a: return "something";
        case b: return "something_else";
        case 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.


回答1:


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.




回答2:


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 "";
}



回答3:


The compiler is clearly confused with different warnings being enabled and the inline return statements. Just make it happy.

enum class E {a, b, c};

QVariant fun(E e) {
     const char* result = "";
     switch (e) {
        case E::a: {
            result = "something"; 
            break;
        }
        case E::b: {
             result = "something_else";
             break;
        }
        case E::c: {
            result = "something_different"; 
            break;
        }
    }
    return result;
}



回答4:


If this all there is, why go to the trouble of a function?

Is the goal simply to mate the key of E::a to "something" and E::b to "something-else" etc.. ?

Are the results preset at compile time? The enum from the OP appears to indicate that the keys are known at compile time.

A simple array would suffice. Unless I'm missing something, nothing really gained by the switch




回答5:


no it may not

Certainly it can.

Believe your compiler. It's smarter than you!

An enumeration is not an exhaustive list of all possible values. It is a set of names for some values of the domain.

Casts are not only possible here; they are to be expected if you wish to provide a stable and robust interface.

So, you either need to provide a default, or tell the compiler via an attribute or intrinsic that you know (based on domain knowledge that it cannot guess) that you know no other possibility will occur.



来源:https://stackoverflow.com/questions/57532056/switch-may-fall-through-no-it-may-not

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!