Search code examples
c++castinglanguage-lawyerenum-class

C-style cast of enum class to reference of underlying type char


Is this legal C++ (>=14), resulting in a char being read and saved into aCode?

enum class ECode : char { Code1 = 'a' };
std::istream& operator>>(std::istream& aIn, ECode& aCode)
{
  return aIn >> (std::underlying_type_t<ECode>&)aCode;
}

I would prefer return aIn >> static_cast<std::underlying_type_t<ECode>&>(aCode) which is not legal, it seems ("cannot cast to reference of unrelated type".)

However, this very similar line is legal, and is what my C-style cast should be identical to:

return aIn >> *static_cast<char*>(static_cast<void*>(&aCode))

Solution

  • As has been noted in comments, there is no strict aliasing violation because char can alias any type.

    In practice I doubt any real compiler would do anything other than the "obvious" implementation, i.e. give the enum the same size and representation as the underlying type. In which case your reinterpret_cast would be well-defined and behave as expected.

    However the Standard (as of C++17) does not appear to guarantee that.

    As far as I can see, it only specifies that any value of the underlying type can be stored in the enum object, and that static_cast can be used losslessly for values in the range of the underlying type.

    There is a language lawyer question here about whether sizeof(ECode) == sizeof(char) must hold, although the answers seem to say "the standard doesn't actually say so but they probably meant it".

    But even if the size is the same there isn't a representation guarantee, e.g. the bits could be stored in some different order and the static_cast transforms the bits.

    In [basic.fundamental] where it specifies the representation of integer types, it even has an explicit footnote saying that enumerations are not integer types.