Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range-for-loops and std::vector<bool>

Why does this code work

std::vector<int> intVector(10); for(auto& i : intVector)     std::cout << i; 

And this doesn't?

std::vector<bool> boolVector(10); for(auto& i : boolVector)     std::cout << i; 

In the latter case, I get an error

error: invalid initialization of non-const reference of type ‘std::_Bit_reference&’ from an rvalue of type ‘std::_Bit_iterator::reference {aka std::_Bit_reference}’

for(auto& i : boolVector) 
like image 882
Valentin Avatar asked Dec 04 '15 01:12

Valentin


People also ask

How do range-based for loops work C++?

C++11 introduced the ranged for loop. This for loop is specifically used with collections such as arrays and vectors. Here, the ranged for loop iterates the array num from beginning to end. The int variable var stores the value of the array element in each iteration.

How does range-based for loop work?

Range-based for loop in C++ Range-based for loop in C++ is added since C++ 11. It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

Are range-based for loops faster?

Range-for is as fast as possible since it caches the end iterator[citationprovided], uses pre-increment and only dereferences the iterator once. Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).

Does C++ have range function?

Remarks. Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .


2 Answers

Because std::vector<bool> is not a container !

std::vector<T>'s iterators usually dereference to a T&, which you can bind to your own auto&.

std::vector<bool>, however, packs its bools together inside integers, so you need a proxy to do the bit-masking when accessing them. Thus, its iterators return a Proxy.
And since the returned Proxy is an prvalue (a temporary), it cannot bind to an lvalue reference such as auto&.

The solution : use auto&&, which will correctly collapse into an lvalue reference if given one, or bind and maintain the temporary alive if it's given a proxy.

like image 99
Quentin Avatar answered Sep 30 '22 21:09

Quentin


std::vector<bool> does not obey the standard container rules.

In particular, its operator[] does 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:

  1. (read-only)

    for (auto i: boolVector)     std::cout << i; 
  2. (read-only, possibly inefficient)

    for (auto const& i: boolVector)       std::cout << i; 
  3. (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.

like image 42
Toby Speight Avatar answered Sep 30 '22 20:09

Toby Speight