开关枚举类的处理始终以clang,gcc和icc返回

问题描述 投票:0回答:1

我通常使用clang来开发代码,并使用所有可能的合理警告(-Wall -Wextra [-Wpedantic])。此设置的好处之一是,编译器检查与所使用的枚举有关的switch语句的一致性。例如下面的代码:

enum class E{e1, e2};

int fun(E e){
    switch(e){
        case E::e1: return 11;
        case E::e2: return 22; // if I forget this line, clang warns
    }
}

clang会抱怨(警告)if我忽略了e1e2的情况,并且[[if没有默认情况。

<source>:4:12: warning: enumeration value 'e2' not handled in switch [-Wswitch] switch(e){
此行为很好,因为

    它在编译时检查枚举和开关之间的一致性,从而使它们成为非常有用且不可分割的一对功能。
  1. 我不需要定义一个人工的default案例,对此我没有什么好要做的。
  2. [它允许我省略一个没有好的东西返回的全局返回值(有时返回值不是像int这样的简单类型,例如,它可能是没有默认构造函数的类型。
  • ((请注意,我使用的是enum class,因此我只假设有效的情况,因为无效的情况只能由调用者端的讨厌转换产生。)

    现在是坏消息:

  • 不幸的是,当切换到其他编译器时,这种方法很快就会崩溃。在GCC和Intel(icc)中,上面的代码警告(使用相同的标志)我没有从非void函数返回。<source>: In function 'int fun(E)': <source>:11:1: warning: control reaches end of non-void function [-Wreturn-type] 11 | } | ^ Compiler returned: 0
    我为此找到的唯一解决方案是,它既有default大小写又返回了无意义的值。

    int fun(E e){ switch(e){ case E::e1: return 11; case E::e2: return 22; default: return {}; // or int{} // needed by GCC and icc } }

    这是很糟糕的,因为我上面提到的原因(甚至没有返回类型没有默认构造函数的情况)。但这也很糟糕,因为我可以再次忘记其中一种枚举情况,现在clang不会因为存在默认情况而抱怨。

    因此,我最终要做的是让这些丑陋的代码在这些编译器上正常工作,并在正确的原因下发出警告。

    enum E{e1, e2}; int fun(E e){ switch(e){ case E::e1: return 11; case E::e2: return 22; #ifndef __clang__ default: return {}; #endif } }

    int fun(E e){ switch(e){ case E::e1: return 11; case E::e2: return 22; } #ifndef __clang__ return {}; #endif }

    还有更好的方法吗?

    这是示例:https://godbolt.org/z/h5_HAs


    非默认构造变量类的情况下,我完全没有好的选择:

    A fun(E e){ switch(e){ case E::e1: return A{11}; case E::e2: return A{22}; } #ifndef __clang__ return reinterpret_cast<A const&>(e); // :P, because return A{} would be invalid #endif }
    https://godbolt.org/z/3WC5v8
    c++11 enums switch-statement return-type enum-class
    1个回答
    0
    投票
    这与enumswitch无关,并且与编译器通过每条路径证明有效的return语句的能力有关。一些编译器在这方面比其他编译器要好。

    正确的方法是在函数的末尾添加

    valid return

    A fun(E e){ switch(c){ case E::e1: return A{11}; ... } return A{11}; // can't get here, so return anything }
    编辑:如果您从无法到达的路径返回,某些编译器(例如MSVC)将抱怨。只需将#if的返回值括在编译器中即可。或者像我经常做的那样,只需要定义一个基于编译器定义的RETURN(x)。
    © www.soinside.com 2019 - 2024. All rights reserved.