The following code doesn't compile
#include <vector>
int main()
{
std::vector<bool> enable(10);
enable[0] |= true;
return 0;
}
giving the error
no match for ‘operator|=’ (operand types are ‘std::vector<bool>::reference {aka std::_Bit_reference}’ and ‘bool’)
In my real life code I have a bit field with values I want to |=
with the result of a function.
There are easy way to express the same idea, but is there any good reason for such an operator not to be available ?
Best Answer
The main reason would be that
std::vector<bool>
is special, and its specification specifically permits an implementation to minimise memory usage.For vectors of anything other than
bool
, the reference type can actually be a true reference (i.e.std::vector<int>::reference
can actually be anint &
) - usually directly referencing an element of the vector itself. So it makes sense for the reference type to support all operations that the underlying type can. This works becausevector<int>
effectively manages a contiguous array ofint
internally. The same goes for all types other thanbool
.However, to minimise memory usage, a
std::vector<bool>
may not (in fact probably will not) work internally with an actual array ofbool
. Instead it might use some packed data structure, such as an array ofunsigned char
internally, where eachunsigned char
is a bitfield containing8
bits. So avector<bool>
of length 800 would actually manage an array of100
unsigned char, and the memory it consumes would be100
bytes (assuming no over-allocation). If thevector<bool>
actually contained an array of800
bool
, its memory usage would be a minimum of800
bytes (since sizeof(bool) must be at least1
, by definition).To permit such memory optimisation by implementers of
vector<bool>
, the return type ofvector<bool>::operator[]
(i.e.std::vector<bool>::reference
) cannot simply be abool &
. Internally, it would probably contain a reference to the underlying type (e.g. aunsigned char
) and information to track what bit it actually affects. This would make all op=
operators (+=
,-=
,|=
, etc) somewhat expensive operations (e.g. bit fiddling) on the underlying type.The designers of
std::vector<bool>
would then have faced a choice betweenspecify that
std::vector<bool>::reference
support all the op=
and hear continual complaints about runtime inefficiency from programmers who use those operatorsDon't support those op
=
and field complaints from programmers who think such things are okay ("cleaner code", etc) even though they will be inefficient.It appears the designers of
std::vector<bool>
opted for option 2. A consequence is that the only assignment operators supported bystd::vector<bool>::reference
are the stock standardoperator=()
(with operands either of typereference
, or of typebool
) not any of the op=
. The advantage of this choice is that programmers get a compilation error if trying to do something which is actually a poor choice in practice.After all, although
bool
supports all the op=
using them doesn't achieve much anyway. For example,some_bool |= true
has the same net effect assome_bool = true
.