std::vector<bool> does not obey the standard container rules.
In particular, its iterators' operator* do not return bool&.
The loop in the invalid code
#include <vector>
#include <iostream>
int main() {
  std::vector<bool> boolVector(10);
  for (auto& i: boolVector)
      std::cout << i;
}
can be rewritten in any of three ways to iterate through the values:
- (read-only) -  for (auto const i: boolVector)
     std::cout << i;
 
- (read-only, possibly inefficient¹) -  for (auto const& i: boolVector)  
     std::cout << i;
 
- (read/write²) -  for (auto&& i: boolVector)
     std::cout << i;
 
The choice between the first and last is down to whether you need to modify the values in the vector, or just to read them.
Notes:
- I say "possibly inefficient" because it has an unnecessary level of indirection. Any decent optimizer ought to create the same code as for the first sample. 
- for (auto i: boolVector)also gives a read/write view on the vector (because we have made a copy of the proxy object).  But I don't recommend that, because readers will likely expect such writes to have only local effect, as would happen with standard containers.
 - And that's why I use - auto const ifor the read-only case; alternatively we could obtain a proxy-of-const using- boolVector | std::views::as_const(since C++23) or by using a const reference to the vector (- for (auto const& v = boolVector; auto i: v)).