Section 9.6/3 in C++11 is unusually clear: "A non-const reference shall not be bound to a bit-field." What is the motivation behind this prohibition?
I understand that it's not possible to directly bind a reference to a bitfield. But if I declare something like this,
struct IPv4Header {
std::uint32_t version:4, // assumes the IPv4 Wikipedia entry is correct
IHL:4,
DSCP:6,
ECN:2,
totalLength:16;
};
why can't I say this?
IPv4Header h;
auto& ecn = h.ECN;
I'd expect the underlying code to actually bind to the entire std::uint32_t
that contains the bits I'm interested in, and I'd expect read and write operations to generate code to do the appropriate masking. The result might be big and slow, but it seems to me that it should work. This would be consistent with the way the Standard say that references to const
bitfields work (again from 9.6/3):
If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly.
This suggests that writing to bitfields is the problem, but I don't see what it is. I considered the possibility that the necessary masking could introduce races in multithreaded code, but, per 1.7/3, adjacent bitfields of non-zero width are considered a single object for purposes of multithreading. In the example above, all the bitfields in an IPv4Header
object would be considered a single object, so multithreaded code attempting to modify a field while reading other fields would, by definition, already be racy.
I'm clearly missing something. What is it?