I found out some interesting thing when I programming:
enum class Foo {
FOO_THING,
FOO_TOO
};
int main() {
Foo foo{1}; // It is OK
Foo foo2(1); // It is an invalid
}
Could you tell me, why foo{1}
is OK for compiler, and why foo2(1)
is invalid ?
Compiler GCC (g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0
) says:
$ g++ -Wall -std=c++17 foo.cpp
error: cannot convert ‘int’ to ‘Foo’ in initialization
Foo foo2(1);
I really want to know underlying mechanics. :)))
Edit: Maybe it is some compiler 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.
This makes it possible to introduce new integer types (e.g. SafeInt) that enjoy the same existing calling conventions as their underlying integer types, even on ABIs that penalize passing/returning structures by value.
This syntax is safe and will not interfere with legacy code (written before c++11) because both scoped enums and list-initialization did not exist at the time. Furthermore, as reported in the quote, this enables the use of new integer types (like those of the SafeInt library) without the need to force a static cast for enum types in code that conforms to modern c++ syntax.
C++17-specific documentation has the following for braced initializer
Otherwise, if T is a enumeration type that is either scoped or unscoped with fixed underlying type, and if the braced-init-list has only one initializer, and if the conversion from the initializer to the underlying type is non-narrowing, and if the initialization is direct-list-initialization, then the enumeration is initialized with the result of converting the initializer to its underlying type.
So foo
seems to be conforming valid C++17, but foo2
being not braced initialized is not valid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With