编译器警告(等级 4)C4471

“enumeration”:未区分范围的枚举的前向声明必须有基础类型(假定为 int)

发现未区分范围的枚举的前向声明没有基础类型的说明符。 默认情况下,Visual C++ 假定 int 为枚举的基础类型。 如果在枚举定义中使用了不同的类型,例如指定了不同的显式类型,或者初始化表达式隐式设置了不同的类型,则可能会导致问题。 你可能还会有可移植性问题;其他编译器不假定 int 为枚举的基础类型。

此警告默认处于关闭状态;可以使用 /Wall 或 /wN4471 在命令行上启用它,或者在源文件中使用#pragma warning

示例

在某些情况下,此警告是虚假的。 如果定义后显示枚举的前向声明,则可能会触发此警告。 例如,此代码有效,即使它可能导致 C4471:

// C4471a.cpp
// Compile with: cl /c /w14471 C4471a.cpp
enum Example { item = 0x80000000UL };
enum Example;    // Spurious C4471
// ...

一般情况下,使用未区分范围的枚举的完整定义而不是前向声明是安全的。 可以将定义放在头文件中,并将其包含在引用它的源文件中。 这适用于为 C++98 及更高版本编写的代码。 为了实现可移植性和易于维护,建议使用此解决方案。

// C4471b.cpp
// Compile with: cl /c /w14471 C4471b.cpp
enum Example;    // C4471
// To fix, replace the line above with the enumeration definition:
// enum Example { item = 0x80000000UL };
// ...

在 C++11 中,可以将显式类型添加到未区分范围的枚举及其前向声明中。 仅当复杂的标头包含逻辑阻止使用定义而不是前向声明时,才建议使用此解决方案。 此解决方案可能会导致维护问题:如果更改用于枚举定义的基础类型,则还必须更改所有要匹配的前向声明,否则代码中可能会存在无提示错误。 可以将前向声明放到头文件中,以最小化此问题。

源文件 C4471c.cpp

// C4471c.cpp
// Client code for enumeration defined in C4471d.cpp
// Compile with: cl /c /w14471 C4471c.cpp C4471d.cpp
enum Example;    // C4471, int assumed
// To fix, replace the lines above with the forward declarations:
// enum Example : unsigned;
// ...

源文件 C4471d.cpp

// C4471d.cpp
// Definition for enumeration used in C4471c.cpp
// Compile with: cl /c /w14471 C4471c.cpp C4471d.cpp
enum Example : unsigned { item = 0x80000000 }; // explicit type
// ...

如果为枚举指定显式类型,建议同时启用默认为开启的警告 C4369。 这标识了枚举项需要与显式指定类型不同的类型的情况。

可以更改代码,使用区分范围的枚举(C++11 中的新增功能)。 必须更改使用枚举类型的定义及任何客户端代码,以使用区分范围的枚举。 如果存在命名空间污染问题,建议使用区分范围的枚举,因为定义的枚举项的名称受限于枚举的范围。 区分范围的枚举的另一个特征是,其成员不能隐式转换为另一个整型或枚举类型,这可能是难以察觉的 bug 的来源。

源文件 C4471e.cpp

// C4471e.cpp
// Client code for scoped enumeration defined in C4471f.cpp
// Compile with: cl /c /w14471 C4471e.cpp C4471f.cpp
enum Example;    // C4471
// To fix, replace the line above with the forward declaration:
// enum class Example;
// ...

源文件 C4471f.cpp

// C4471f.cpp
// Definition for scoped enumeration used in C4471e.cpp
// Compile with: cl /c /w14471 C4471e.cpp C4471f.cpp
enum class Example { item = 0 };
// ...