使用int初始化枚举类

时间:2018-06-06 10:09:37

标签: c++ enums initialization c++17

我编程时发现了一些有趣的事情:

enum class Foo {
  FOO_THING,
  FOO_TOO
};

int main() {
  Foo foo{1};    // It is OK
  Foo foo2(1);   // It is an invalid
}

你能告诉我,为什么foo{1}对编译器没问题,为什么foo2(1)无效?

编译器GCC(g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0)说:

$ g++ -Wall -std=c++17 foo.cpp

  error: cannot convert ‘int’ to ‘Foo’ in initialization
  Foo foo2(1);

我真的想知道潜在的机制。 :)))

编辑:也许这是一些编译器错误......

2 个答案:

答案 0 :(得分:4)

C ++ 17特定的documentation具有以下支持初始化程序

  

否则,如果T是一个作用域的枚举类型   没有固定的底层类型,如果braced-init-list有   只有一个初始化程序,如果从初始化程序转换为   底层类型是非缩小的,如果初始化是   direct-list-initialization,然后使用初始化枚举   将初始值设定项转换为其基础类型的结果。

所以foo似乎符合有效的C ++ 17,但foo2未被支持初始化是无效的。

答案 1 :(得分:3)

要理解为什么这两种语法不是合法的原因,你必须考虑使用标准c ++ 11引入作用域枚举以强制执行静态类型检查并具有作用域标识符(即不再有名称污染)。

Foo foo(1)无法正常工作,因为禁止从整数类型到作用域枚举的隐式转换,否则会失去作用域枚举的好处,并避免在重载解析期间发生冲突。

使用Foo foo{1}时,您使用的是{+ 3}},它也是使用c ++ 11引入的,但是使用c ++ 17进行了升级,其中包含从int值到枚举的隐式转换list initialization,如果满足一系列要求:

  

两种范围的枚举类型和未范围的枚举类型   固定的底层类型可以从没有a的整数初始化   如果满足以下所有条件,则使用列表初始化强制转换:

     
      
  1. 初始化是直接列表初始化

  2.   
  3. 初始化列表只有一个元素

  4.   
  5. 枚举是作用域还是未作用域,基础类型已修复

  6.   
  7. 转换不是缩小范围。

  8.         

    这使得引入新的整数类型(例如SafeInt)成为可能,这些整数类型享有与其基础整数相同的现有调用约定   类型,甚至在ABI上惩罚通过/返回结构   值。

这种语法是安全的,不会干扰遗留代码(在c ++ 11之前编写),因为当时不存在作用域枚举和列表初始化。此外,正如引文中所报告的,这使得能够使用新的整数类型(如SafeInt库的那些),而无需在符合现代c ++语法的代码中强制执行枚举类型的静态强制转换。