Why can I use curly brackets to initialize one enum class with a value from another enum class?
Asked Answered
A

2

23

I have found the following behavior of Clang-12, Clang-13 and Clang-14 with c++17 standard:

enum class FOO {
  VALUE
};

enum class BAR {
  VALUE
};

FOO value1{BAR::VALUE}; // OK
FOO value2 = BAR::VALUE; // Error

Why is there a difference? I would expect enum class to be 100% type safe.

Compiler Explorer

Agatha answered 21/6, 2022 at 20:41 Comment(2)
Seems this is fixed for Clang 15: godbolt.org/z/MEhEz33Ph (can reproduce this)Inveteracy
@Artyer, Can you please add this as answer. I'll accept it.Agatha
D
17

This is CWG issue 2374.

In C++17, before the resolution of this issue, direct-list-initialization of an enumeration with a fixed underlying type by a single expression was specified to always be equivalent to a functional style cast. A functional style cast then would be equivalent to a static_cast and that would actually be allowed between different enumeration types (by going through the promoted underlying type).

With the issue resolution this path is taken only if the initializer expression is implicitly convertible to the enumeration type, which doesn't allow for conversion between different enumeration types.

That seems to have been an oversight in the resolution of a prior issue for C++17: CWG 2251

It seems that Clang decided to faithfully implement CWG 2251 and only revert this special case once CWG 2374 was resolved and the fix for the latter will be included with Clang 15.

For GCC the same seems to apply before GCC 12.

MSVC seems to forbid the conversion only in conformance mode (/permissive- or C++20 or later mode) and only since v19.25.

Derward answered 21/6, 2022 at 21:15 Comment(0)
A
6

Both of these produce compiler errors for me in VS2022 under C++17 and C++20.

GCC 9.3.0 on Ubuntu also produce compiler errors.

Perhaps this is a Clang-specific bug or extension? (Maybe Clang attempts to automatically cast when using bracket initialization?)

I was able to reproduce this behavior only when using Clang up to version 14.

Compiler error with Clang (trunk):

error: cannot initialize a variable of type 'FOO' with an rvalue of type 'BAR'
FOO value{BAR::VALUE};
          ^~~~~~~~~~
Argueta answered 21/6, 2022 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.