Why does the disjunction assignment operator |= not work with vectors of bools?
Asked Answered
A

1

14

If I have a vector<bool> vec_bool then I cannot modify the contents of the vector using the |= assignment operator. That is, the lines

vec_bool[0] |= true;
vec_bool[0] |= vec_bool[1];

give compiler errors, while the lines

bool a = false;
a |= true;
a |= vec_bool[0];
vec_bool[0] = vec_bool[0] | vec_bool[1];
vec_bool[0] = vec_bool[0] || vec_bool[1];

vector<int> vec_int(3);
vec_int[0] |= vec_int[1];

do not. What is the reason for this?

The error given (by gcc) is:

test.cpp:21:17: error: no match for ‘operator|=’ (operand types are ‘std::vector::reference {aka std::_Bit_reference}’ and ‘bool’)

Alvarez answered 3/10, 2017 at 9:47 Comment(6)
You have to remember that std::vector<bool> is not an ordinary vector. It's not an actual vector of bool, but more like a vector of bits, whose implementation is not specified by the C++ specification.Varien
Possible duplicate of Why does std::vector<bool> has no .data()?Josephjosepha
You can take a look at en.cppreference.com/w/cpp/container/vector_bool for more information about itFremantle
@GauravSehgal related, but not a duplicate. The same underlying cause, but very different question/goal.Dudgeon
It is probably worth mentioning that std::array<bool> has not this kind of optimization, so it behaves different ([...]This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member.[...]). However you lose the ability to resize it. For example.Breakout
To paraphrase Scott Meyers "There are two problems with vector<bool>. It is not a vector. It does not store bools"Septuplicate
P
18

The reference returned from operator[] of std::vector<bool> is not an alias for bool&, as it is for the primary specialization of std::vector. It is rather specified by the C++ standard as this:

// bit reference:
class reference {
  friend class vector;
  reference() noexcept;
public:
  ~reference();
  operator bool() const noexcept;
  reference& operator=(const bool x) noexcept;
  reference& operator=(const reference& x) noexcept;
  void flip() noexcept;     // flips the bit
};

And as you can see, there is no operator |= declared. So you can't apply it on the reference returned from vec_bool[0].

The reason that vec_bool[0] = vec_bool[0] | vec_bool[1]; works is that there are overloads above that facilitate it. operator bool() converts the two operands of the built-in | into bool values. And then the assignment operator of reference assigns the result back to vec_bool[0].

As specified by the C++ standard, std::vector<bool> isn't a particularly good abstraction, IMO.

Parfait answered 3/10, 2017 at 9:58 Comment(3)
Thank you! Could you perhaps tell me if vector<bool> is the only type of vector that deviates from the 'standard' implementation of the vector type?Alvarez
@MeesdeVries - It's the only one that the C++ standard mandates to deviate from the primary declaration. All others you can assume to be of the primary template.Parfait
... which is to say, others may be specialized for performance reasons, but you can't detect that in portable code.Lading

© 2022 - 2024 — McMap. All rights reserved.