为什么我可以使用大括号用另一个枚举类的值来初始化一个枚举类?

Ale*_*lex 23 c++ enums initializer-list

我发现 Clang-12、Clang-13 和 Clang-14 具有以下标准行为c++17

enum class FOO {
  VALUE
};

enum class BAR {
  VALUE
};

FOO value1{BAR::VALUE}; // OK
FOO value2 = BAR::VALUE; // Error
Run Code Online (Sandbox Code Playgroud)

为什么会有差异?我期望enum class100% 类型安全。

编译器资源管理器

use*_*522 17

这是CWG 问题 2374

在 C++17 中,在解决此问题之前,通过单个表达式对具有固定基础类型的枚举进行直接列表初始化被指定为始终等效于函数式风格转换。那么函数式风格转换就相当于static_cast并且实际上允许在不同的枚举类型之间进行转换(通过升级的基础类型)。

通过问题解决,仅当初始值设定项表达式可隐式转换为枚举类型时才采用此路径,这不允许在不同枚举类型之间进行转换。

这似乎是解决 C++17 先前问题时的疏忽:CWG 2251

看来 Clang 决定忠实地实现 CWG 2251,并且只有在 CWG 2374 得到解决后才恢复此特殊情况,并且后者的修复将包含在 Clang 15 中。

对于 GCC,这似乎同样适用于 GCC 12 之前的情况。

MSVC 似乎仅在一致性模式(/permissive-或 C++20 或更高版本模式)下且仅从 v19.25 起禁止转换。


小智 6

这两个都会在 C++17 和 C++20 下的 VS2022 中产生编译器错误。

Ubuntu 上的 GCC 9.3.0 也会产生编译器错误。

也许这是 Clang 特定的错误或扩展?(也许 Clang 在使用括号初始化时会尝试自动转换?)

当使用 Clang版本 14 之前,我才能重现此行为。

Clang 编译器错误(主干):

error: cannot initialize a variable of type 'FOO' with an rvalue of type 'BAR'
FOO value{BAR::VALUE};
          ^~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)