打开枚举时的编译器警告
Compiler warning when switching on an enum
enum ENUM(Option1,Option2,Option3);
string func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
}
}
这将编译并工作,但会给出一个编译器警告,指出并非所有控制路径都返回。但是,如果您正确使用枚举,情况并非如此,这不是重点吗?如果添加了另一个 ENUM val,我希望编译失败,但只要涵盖所有情况,我希望它编译无警告。
这是编译器防止错误的强制转换值吗,它只是C++的一部分,需要忍受吗?
在C++中,枚举是不安全的。不能期望枚举值是枚举声明中定义的值之一:
- 它可以是未初始化的(因此是垃圾)
- 您可能
static_cast
来自int
因此,编译器不能期望开关返回,即使您涵盖了枚举的所有元素也是如此。但是,从功能上讲,这确实是一种错误条件。
有两种反应方式:
- 将
default
案例添加到enum
- 在切换后添加语句
为了明智地选择,请记住,编译器可能会(如果您询问它)在switch
没有default
语句的情况下触发警告,只要没有涵盖enum
的所有情况。智能编译器(即Clang)允许将警告单独映射到错误,这极大地帮助捕获这些错误。
因此,您可以决定采取:
- 如果您希望在更新枚举后忘记更改此方法时收到通知,请不要使用
default
- 如果希望能够更新枚举并忽略此开关,请使用
default
最后,您必须决定如何做出反应,请注意使用运行时错误与使用默认语句不一致(最好尽可能在编译时捕获错误):
- 忽略错误并返回一些预定义的值
- 抛出异常(请带有枚举值)
- assert(因此在调试中崩溃,以获得内存转储,并在发布中执行其他操作,例如什么都不做,或者抛出异常)
我个人最喜欢的是一个UNREACHABLE(Text_)
宏,它会在 Debug 中引发内存转储(以便我获得完整跟踪)并记录错误并抛出 Release(以便服务器停止处理此请求,但不完全停止响应)。
这给出了如下代码:
char const* func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
}
UNREACHABLE("func(ENUM)")
}
从编译器的角度来看,枚举的类型是一个整数,因此 x
的值仍然可能是其他情况之一。
通常,我会添加一个触发内部错误的default:
标签。
提示:如果将调用实习生错误包装在无限循环中,则不必发明伪造的返回值。例如:
#define IntErr(x) for(;;) { InternalError(x); }
string func(ENUM x)
{
switch(x)
{
case Option1: return "Option1";
case Option2: return "Option2";
case Option3: return "Option3";
default: IntErr("Unexpected ENUM value");
}
}
如果由于某种原因x
既不是Option1
,也不是Option2
,也不是Option3
,会发生什么?
当然,你可能会争辩说这永远不会发生,但由于该方法必须返回一些东西,你有两个选择:
-
在末尾添加一个
return string("");
。 -
将
default
添加到返回string("")
的switch
。
正如CodeGray指出的那样,第二种选择可以说是更好的风格。您还可以返回空字符串以外的内容。
- 如何修复编译器警告 C6386 和 C6385?
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 为什么布尔开关语句有编译器警告?
- 使用 reverse_iterator 而不是const_reverse_iterator并获得讨厌的编译器警告和错误
- 来自 std::chrono 的编译器警告,但未被使用
- 警告级别为 3 的 int 的 std::vector push_back 处的编译器警告
- 有没有办法在从临时返回按值string_view时获得编译器警告?
- 常量更改而不const_cast<> 为什么没有编译器警告/错误?
- C++ 添加编译器警告,以错误使用自定义打印/日志功能
- 我正在尝试在我的类中创建一个静态成员,但编译器警告我它是未定义的
- 是否可以将移动的变量标记为不再可用,并在使用它时收到编译器警告?
- 为什么我应该始终启用编译器警告
- 对列表类中的泛型方法禁用编译器警告 2100,该泛型方法可能包含指针,也可能不包含指针
- C++ 如何禁用具有不同符号变量比较的特定行的编译器警告?
- CMake:如何将每个资源编译器警告视为错误并抑制特定警告?
- 为什么方法重载或枚举标志定义会触发 gcc7.2 编译器警告?
- 违反严格别名并不总是会产生编译器警告
- (如何)获取有关某个 C++Year 的已弃用/不推荐的功能/构造的编译器警告
- 使用 VS 2015 的编译器警告 4456
- 在嵌套名称说明符中使用枚举(编译器警告)