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’)

Mees de Vries
  • 639
  • 3
  • 24
  • 14
    You have to remember that [`std::vector`](http://en.cppreference.com/w/cpp/container/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. – Some programmer dude Oct 03 '17 at 09:49
  • 2
    Possible duplicate of [Why does std::vector has no .data()?](https://stackoverflow.com/questions/46115669/why-does-stdvectorbool-has-no-data) – Gaurav Sehgal Oct 03 '17 at 09:52
  • 2
    You can take a look at http://en.cppreference.com/w/cpp/container/vector_bool for more information about it – cbuchart Oct 03 '17 at 09:53
  • 1
    @GauravSehgal related, but not a duplicate. The same underlying cause, but very different question/goal. – sehe Oct 03 '17 at 10:01
  • It is probably worth mentioning that [std::array](http://en.cppreference.com/w/cpp/container/array) 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](http://coliru.stacked-crooked.com/a/acc6abad754046cc). – user1810087 Oct 03 '17 at 10:36
  • 1
    To paraphrase Scott Meyers *"There are two problems with `vector`. It is not a vector. It does not store `bool`s"* – Happy Green Kid Naps Oct 03 '17 at 13:32

1 Answers1

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.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Thank you! Could you perhaps tell me if `vector` is the only type of vector that deviates from the 'standard' implementation of the vector type? – Mees de Vries Oct 03 '17 at 10:05
  • 6
    @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. – StoryTeller - Unslander Monica Oct 03 '17 at 10:07
  • 3
    ... which is to say, others may be specialized for performance reasons, but you can't detect that in portable code. – MSalters Oct 03 '17 at 13:17