'Trying to change a value in a vector bool
I'm reading Stroustrup PPP and while doing an exercise, I found this error.
Why I can't change the value of a vector bool?
#include "std_lib_facilities.h"
int main()
{
vector<bool> vecc(2, true);
vecc[1] = true; // I can't do this, returns error.
return 0;
}
The error:
error: cannot bind non-const lvalue reference of type 'bool&' to an rvalue of type 'bool' return std::vector<T>::operator[](i);
Second, when I try with the int type, the problem does not occur.
#include "std_lib_facilities.h"
int main(){
vector<int> vecc = {true, true};
for(bool x : vecc) {cout<<x<<"\n";}
vecc[1] = false; //ok
for(bool x : vecc){cout<<x<<"\n";}
return 0;
}
Output:
1
1
1
0
Edit:
Probably this is because I was using #include "std_lib_facilities.h"
Solution 1:[1]
std_lib_facilities.h defines the following helper template to add a bit of error checking helpful to folks beginning their programming careers:
// trivially range-checked vector (no iterator checking):
template< class T> struct Vector : public std::vector<T> {
using size_type = typename std::vector<T>::size_type;
/* #ifdef _MSC_VER
// microsoft doesn't yet support C++11 inheriting constructors
Vector() { }
explicit Vector(size_type n) :std::vector<T>(n) {}
Vector(size_type n, const T& v) :std::vector<T>(n, v) {}
template <class I>
Vector(I first, I last) : std::vector<T>(first, last) {}
Vector(initializer_list<T> list) : std::vector<T>(list) {}
*/
using std::vector<T>::vector; // inheriting constructor
T& operator[](unsigned int i) // rather than return at(i);
{
if (i<0 || this->size() <= i) throw Range_error(i);
return std::vector<T>::operator[](i);
}
const T& operator[](unsigned int i) const
{
if (i<0 || this->size() <= i) throw Range_error(i);
return std::vector<T>::operator[](i);
}
};
T& operator[](unsigned int i) and its const variant return a reference to T and in this case T is bool. To get the element it calls through to std::vector's operator[] to do the grunt work.
Unfortunately std::vector<bool> is not a proper library container. Because it packs bits rather than storing bools, it can't return a reference to a bool from the element access methods. It doesn't have any bools to reference. Instead it returns a groovy reference class that conceals the bit packing from sight and usually makes life a bit easier. Under most circumstances the element access methods will behave exactly the same way as a regular vector.
But not this time. It's not returning a reference and it's not returning a reference to a bool so the simple pass-through fails to compile.
Common work arounds are to use a std::vector containing some small integer type or an enum or use a std::deque<bool> which can be used largely the same way and doesn't have a bit-backing specialization. If the size is known at compile time, consider using a std::bitset.
Solution 2:[2]
The standard library provides a specialization of std::vector for the type bool, which may be optimized for space efficiency. This stores bool as 1 bit saving you a lot of memory for large vectors.
The problem with that is that you can not return a reference to a bit so the standard library is supposed to return reference object wrapper around the bit that allows assignment. The object keeps a reference to the vector and the bit position you asked for and has an operator=() that calls std::vector<bool>::assign().
The example code for this even has this:
std::vector<bool> is_prime(N, true);
is_prime[0] = is_prime[1] = false;
Only thing I can think of is that your compiler has an old version of the STL or a bad implementation that does have a vector specialization but without the wrapper reference object. Try
vecc.assign(1, true);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Goswin von Brederlow |
