【发布时间】:2020-02-26 03:14:13
【问题描述】:
我通常使用clang 开发代码,尽我所能使用所有合理的警告 (-Wall -Wextra [-Wpedantic])。这个设置的好处之一是编译器检查switch stataments 与所使用的枚举的一致性。例如在这段代码中:
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 会抱怨(警告)如果:我省略了e1 或e2 的情况,并且没有默认情况。
<source>:4:12: warning: enumeration value 'e2' not handled in switch [-Wswitch]
switch(e){
这种行为很棒,因为
- 它在编译时检查枚举和开关之间的一致性,使它们成为非常有用且不可分割的一对功能。
- 我不需要定义一个人为的
default案例,我不会为此做任何好事。 - 它允许我省略一个全局返回,我不会为它返回一个好东西(有时返回不是像
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{} could be invalid
#endif
}
【问题讨论】:
标签: c++ c++11 enums switch-statement enum-class