Bar*_*kPL 7 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
}
Run Code Online (Sandbox Code Playgroud)
你能告诉我,为什么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);
Run Code Online (Sandbox Code Playgroud)
我真的想知道潜在的机制.:)))
编辑:也许是一些编译器bug ...
To understand the reasons why the two syntax are not both legit you must consider that scoped enums were introduced with standard c++11 to enforce static type checking and have scoped identifiers (i.e. no name pollution anymore).
Foo foo(1) is not working because implicit conversion from integer type to scoped enum is forbidden, otherwise you lose the benefit of scoped enums, and to avoid conflicts during overload resolution.
When using Foo foo{1} you are using list initialization that was introduced with c++11 too, but got an upgrade with c++17, that consist in implicit conversion from int value to enum as reported here, if a set of requirements are satisfied:
Both scoped enumeration types and unscoped enumeration types whose underlying type is fixed can be initialized from an integer without a cast, using list initialization, if all of the following is true:
the initialization is direct-list-initialization
the initializer list has only a single element
the enumeration is either scoped or unscoped with underlying type fixed
the conversion is non-narrowing.
这使得引入新的整数类型(例如 SafeInt)成为可能,这些新的整数类型与它们的底层整数类型享有相同的现有调用约定,甚至在按值惩罚传递/返回结构的 ABI 上也是如此。
这种语法是安全的,不会干扰遗留代码(在 c++11 之前编写),因为作用域枚举和列表初始化当时都不存在。此外,正如引用中所报道的,这使得可以使用新的整数类型(如 SafeInt 库的整数类型),而无需在符合现代 C++ 语法的代码中强制对枚举类型进行静态转换。