0

Why the code below compiles (i.e. the element's value could be modified) whereas the reference of vector<bool> is a prvalue? I would be very grateful to have some help with this question.

Here is the related code:

#include <vector>
#include <iostream>

int main()
{
    std::vector<bool> v(10,true);
    for (auto&& e : v)
    {
        std::cout << e << std::endl;
        e = false;  //I wonder why this expression works whereas the ref of vector<bool> is a prvalue?
    }    

    for (auto&& e : v)
    {
        std::cout << e << std::endl;  
    }    
}
John
  • 2,963
  • 11
  • 33
  • 2
    Do you know why `v[0] = false;` compiles? – HolyBlackCat Jun 10 '20 at 06:00
  • @HolyBlackCat If `v` is the type of `vector` or etc, I can understand it as their reference is lvalue. But the reference of `vector` is prvalue (through, I do not understand it at all, some experts told me and I recited it.). I am confused. It's amazing that I can do an assignment to a prvalue! – John Jun 10 '20 at 06:04
  • 1
    You keep on saying "reference" which is usually meant to be an lvalue-reference (using single `&`), but what you have is an rvalue-reference (double `&&`) which makes it a very different thing. This is probably an issue that needs a language-lawyer to answer with references to sections in the C++ specification. – Some programmer dude Jun 10 '20 at 06:07
  • @Someprogrammerdude Some experts told me the reference of `vector` is prvalue. Though I do not understand it at all and I have not found any evidence yet, as their high reputation on SO, I believe they are right. – John Jun 10 '20 at 06:13

1 Answers1

4

vector<bool> is special. Unlike vectors of other types, it doesn't store actual bools (that would require using 1 byte per bool). Instead, it stores them packed as bits in an array of integers (1 bit per value; for example, it might store an array of unsigned char and pack 8 bools as bits into a single unsigned char).

Because there are no actual bools in the vector<bool>, you can't form references to them. So the operations that would normally yield references (such as dereferencing an iterator) can't do so.

Some experts told me the reference of vector<bool> is prvalue. Though I do not understand it at all. But as their high bonus on SO, I believe they are right.

What they mean is that dereferencing a vector<bool> iterator returns a prvalue (which simply means that it returns by value rather than by reference).

By "reference of vector<bool>" they likely meant vector<bool>::reference and vector<bool>::const_reference, which refer to the types that you get when dereferencing an iterator (regular and const respectivelty) of vector<bool>. Normally, for vector<T> (T != bool) they would be equal to T & and const T & respectively, but for vector<bool>, const_reference is bool and reference is some class.

The vector<bool>::reference class has some overloaded operators to make it work like a reference. In particular, it has operator= overloaded, so you can assign bools to it. (Which sets a single specific bit of the vector to 1.)

As for why for (auto&& e : v) works... auto && is a forwarding reference. I'm not going to explain how forwarding references work (look it up!), but your loop is equivalent to for (std::vector<bool>::reference &&e : v) (if it wasn't a vector of bool, it would instead become for (ElementType &e : v)).

When you do e = false;, you invoke the overloaded operator= of std::vector<bool>::reference.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • 1
    TL;DR Dereferencing an iterator and `operator[]` of `std::vector` returns an object of a proxy class ([`std::vector::reference`](https://en.cppreference.com/w/cpp/container/vector_bool/reference)), which has overloaded assignment `operator=`. This serves for setting the corresponding internally packed vector element. – Daniel Langr Jun 10 '20 at 06:57
  • @HolyBlackCat Thank you for the clarifiaction. I can understand what you mean to some degree. I have no doubt with your answer. I am just a little confused. As per the documentation(https://en.cppreference.com/w/cpp/container/ **vector_bool/reference** ), which clearly says that [emphasis mine]:The std::vector specialization defines std::vector::reference as a publicly-accessible nested class. std::vector::reference proxies the behavior of references to a single bit in std::vector.The primary use of std::vector::reference is to **provide an l-value** that can be returned from operator[]. – John Jun 10 '20 at 07:01
  • 1
    @John That sentence is quite misleading in my opinion. `operator[]` of `std::vector` returns `reference` by value. How its call-expression can by lvalue? See [this relevant question](https://stackoverflow.com/q/62296219/580083). It seems that the documentation is wrong here (even cppreference is not perfect; if you are in doubts, look to the Standard :). – Daniel Langr Jun 10 '20 at 07:04
  • @John No idea what they mean by that. Maybe they were trying to say that `vector::reference` is returned by `operator[]` instead of an lvalue reference. – HolyBlackCat Jun 10 '20 at 07:07
  • @DanielLangr That question is posted by myself! :) It's a pity that it has been closed quickly. – John Jun 10 '20 at 07:27
  • @HolyBlackCat Thank you for the clarification. Though I don't fully understand your posted answer . I would go out of my way to study it. – John Jun 10 '20 at 07:31