GCC 是否正确警告格式字符串与作用域枚举不匹配?

Is GCC correct to warn of format string mismatch with a scoped enum?

当在 varargs 上下文中使用范围枚举时,它被定义为作为其基础类型传递,如“Can I use enum class values as arguments to varargs functions?”中的回答,据我所知,这是唯一情况枚举将被隐式转换,就像无作用域的枚举一样。

考虑这个程序:

enum Foo : char { F };
enum class Bar : char { B };

#include <cstdio>
int main()
{
    return !std::printf("%c\n", Foo::F)
        +  !std::printf("%c\n", Bar::B);
}

编译器(g++ 版本 6.3.0)对 Foo 的第一次打印感到满意,但在我传递 Bar:

时抱怨
0.cpp: In function ‘int main()’:
0.cpp:10:34: warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘Bar’ [-Wformat=]
         +  !printf("%c\n", Bar::B);
                                  ^

g++ 版本 4.8.2 没有抱怨这个,但是 g++ 6.3.0 有(这就是我现在担心的原因)。当存在实质性不匹配时,例如使用 %f%s,或者如果我将 Foo 更改为使用 long 基础类型,两个版本都会抱怨第一次打印;这就是为什么我启用 -Wformat.

我知道警告不是标准一致性问题,我知道如何更改我的代码来解决这些问题(例如,使用 How can I output the value of an enum class in C++11? 答案中的函数),但我也相信警告是如果它们产生误报,则无济于事。当枚举的基础类型与格式字符串中的相应转换规范匹配时,将作用域枚举传递给格式化的 I/O 函数是否存在潜在的实际危害?

来自 this scoped enumeration reference:

There are no implicit conversions from the values of a scoped enumerator to integral types, ...

[强调我的]

这意味着无论基类型如何,作用域枚举都不会隐式转换为 int(或任何其他整数类型)。您必须明确地进行转换,例如static_cast(接上一引):

... although static_cast may be used to obtain the numeric value of the enumerator.


此外,来自 this variadic argument reference

bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion

[再次强调我的]


并回答你的问题,如果 GCC 警告你是正确的:是的,它是正确的。你这样做是不正确的。