Scoped enum with underlying type 'bool' truncates differently across compilers

Viewed 84

I recently discovered that C++ Scoped enums are allowed to use bool as the underlying type, which somewhat makes sense since std::is_integral_v<bool> is true.

However, I've also found that the truncation behavior when static_casting to a type made this way causes different results across compilers. In particular:

enum class Option : bool {
    No = false,
    Yes = true,
};

constexpr auto v = static_cast<Option>(8); 

std::cout << static_cast<bool>(v) << std::endl;

Compiler Explorer

GCC reports this result as false, whereas Clang and MSVC report true (MSVC can be seen by checking the mov cl, 1 prior to calling).

This value reports as true for GCC if the last bit is set, so static_cast<Option>(9) will result in true as the underlying type:

constexpr auto v = static_cast<Option>(9); 

std::cout << static_cast<bool>(v) << std::endl;

Compiler Explorer

It seems that GCC treats the static_cast as a 1-bit unsigned integral value cast, and thus truncates the value to 1 bit, much like a uint32_t would narrow to a uint8_t, whereas Clang and MSVC both treat it like a normal boolean cast using n > 0.

Which compiler here is correct? If this is some form of undefined behavior, why can it be used in a constexpr expression?


Note: An obvious workaround is to use static_cast<Option>(static_cast<bool>(...)), but I'm curious about what behavior should be expected here -- if any. This behavior appears to be occur in all C++ versions that support scoped enums (from and up).

0 Answers
Related