代码之家  ›  专栏  ›  技术社区  ›  Aykhan Hagverdili

开关可能会掉进去(不可能)

  •  1
  • Aykhan Hagverdili  · 技术社区  · 5 年前

    在GCC7上,我启用了qt creator 4.9上的大多数警告。现在我有了一个switch语句,它涵盖了所有枚举值。如果我加一个 default: 我收到警告(来自qt creator):

    warning: default label in switch which covers all enumeration values
    

    如果我移除 违约: 我得到了另一个警告(来自GCC):

    error: this statement may fall through [-Werror=implicit-fallthrough=]  
           }  
           ^
    
    error: all warnings being treated as errors
    

    我该怎么办?关闭警告?它们很有用,我不想关掉它们,但是 Wimplicit-fallthrough 好像有毛病。

    [[fallthrough]] 没有帮助,因为 case 以…结尾 return 因此我(从Qt创建者那里)得到:

    warning: fallthrough annotation in unreachable code
    

    __attribute__ ((fallthrough)) 也没做什么。也没有 /* FALLTHRU */ [[gnu::fallthrough]] // fall through . 大概是因为 -pedantic ?

    例子:

    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?
        }
    }
    

    希望我试过的东西表明我的问题不是 this this 或者其他类似的问题,因为它们不能解决我的问题。

    4 回复  |  直到 5 年前
        1
  •  6
  •   Miles Budnek    5 年前

    考虑 fun(static_cast<E>(42)) . 这是一个定义很好的转换,但是来自您问题的函数将在不返回的情况下到达末尾,并且您的程序的行为将是未定义的。这就是为什么GCC警告说控制可能会到达非空函数的末尾。

    为什么不加一个 default 案例?考虑如果有人返回并将另一个常量添加到 E ,但忘记更新 fun . 没有 违约 ,GCC会很有帮助地警告您,开关不能处理所有 e 的常量。如果您添加 违约 凯斯,你已经击败了那个非常有益的保护。

    那么什么是正确的事情呢 TM 要做什么?返回默认值(或 throw 或者打电话 abort() 在函数结束时,在 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()
    }
    

    这给了你两个世界中最好的。如果有人传递的值不是预先定义的枚举器常量之一,它将以一种定义良好的方式运行。如果有人在 e 忘了更新 乐趣 然后编译器仍然会发出警告。

    为了进一步讨论,Jason Turner在他的 CppCon 2018 talk 一块表也值。

        2
  •  2
  •   selbie    5 年前

    如果我的第一个回答不满意,这也许会。这就是我在本地解决问题的方法:

    QVariant fun(E e) {
         switch (e) {
            case a: return "something";
            case b: return "something_else";
            case c: return "something_different";
        }
        return "";
    }
    
        3
  •  1
  •   selbie    5 年前

    编译器显然会与启用的不同警告和内联返回语句混淆。让它快乐。

    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
  •  1
  •   jdw    5 年前

    如果这一切都存在,为什么要去一个函数的麻烦?

    目标只是为了配合 E::a "something" E::b "something-else" 等。。?

    结果是否在编译时预设?这个 enum 从op中显示,表示在编译时知道这些键。

    一个简单的数组就足够了。除非我错过了什么,否则 switch

        5
  •  1
  •   Lightness Races in Orbit    5 年前

    不,可能不会。

    当然可以。

    相信你的编译器。比你聪明!

    枚举不是所有可能值的详尽列表。它是一组 一些 域的值。

    强制转换不仅在这里是可能的;如果您希望提供一个稳定和健壮的接口,那么可以预期强制转换。

    因此,您要么需要提供 default 或者通过属性或内部函数告诉编译器您知道(基于域知识,它无法猜测)您 知道 不会有其他可能性。