与 C++11 `enum class` 的 ABI 兼容性保留

ABI compatibility preservation with C++11 `enum class`

这几乎与 Does adding enumerators into enum break ABI? 相同的问题,但 enum class 由 C++11 引入。

根据我对 this page 的理解,我可以通过为我的枚举定义 底层类型 来简单地拥有稳定的 ABI:

enum class Foo : uint32_t
{
    x, y, z
}

我会说这很好用,例如

enum class Foo : uint8_t { x = 257 }

不会编译。这意味着编译器不再默默地改变我的枚举的大小,因此我最终不会破坏二进制兼容性。

我说得对吗?

我相信 the accepted answer to the referenced question 回答了大部分关于 ABI 兼容性的问题。我可以在这里重复一遍,但我看不出有多大价值。

为了解决您关于 C++11 作用域枚举的具体问题,您的示例:

enum class Foo : uint8_t { x = 257 }

格式不正确,因为它需要缩小转换,需要实现来提供诊断,但如果实现仅使其发出警告,它可能会编译。如您所问,编译器不会默默地更改基础类型的大小。

我们可以从 C++ 标准草案中看出这一点 dcl.enump5:

Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be fixed. Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type. If the underlying type is not fixed, the type of each enumerator prior to the closing brace is determined as follows: ...

converted constant expression禁止收缩转换,来自expr.constp5:

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only

...

  • integral conversions other than narrowing conversions,

...

OP在这里。

我发现,我认为值得一提的是,C++11 有这么好的 std::underlying_type

我觉得可以用,配合is_samestatic assertions,创建一些保护措施以防止 ABI 因枚举而发生意外更改。

我认为(但我没有尝试)如果一个人正在使用某个库,并且预先存在的枚举未指定基础类型,这尤其重要。