1

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))
6
  • Duplicate? Commented Jun 10, 2020 at 22:09
  • @Quentin Interesting. As the 5-year-old answer there is "this is not clear from the standard", I would still like to get answers for newer C++ versions. I'll remove the C++14 tag. Commented Jun 10, 2020 at 22:11
  • I recommend putting a bounty on the existing question, because I don't think anything's changed in this regard (and I'd frown at this code anyway tbh - why not extract into a char, then proper cast to an ECode and finally assign? it'll be super quick) Commented Jun 10, 2020 at 22:17
  • 4
    One way this question differs from the other one is that accessing an object via type char never violates the strict aliasing rule. But I don't see any guarantees relating value representations of an enumeration type and its underlying type. Commented Jun 10, 2020 at 22:23
  • @AsteroidsWithWings That is exactly the code I have, but this still sparks the question. I like (to at least know of legal) one-liners, if only for the jest of it, even if they don't pass a code review ;) Commented Jun 10, 2020 at 22:31

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

The C++17 definition of enum class byte : unsigned char {} ; seems to imply that both size and representation must be identical to unsigned char. I wonder if this is generalizable, but it probably isn't (are they stretching the standard here? :) ). I also wonder why they don't just write what they mean ...
@FelixDombek it seems there's an oversight somewhere (not uncommon in the standard) , e.g. perhaps whoever wrote the std::byte addon didn't realize the underspecification of the enum size

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.