+ 3
References C++
I am having trouble understanding why certain types bind to &, others to &&, and some to both. I attached a sample code, with comments that indicate what does and doesn't work, and I was hoping someone could explain simply why this is the case? https://code.sololearn.com/cZnJgXoHYSEl
5 Answers
+ 3
This is because "vector <bool>" is not what you think it is.
It's special because the language standards allow implementation writers to space optimize the containers of type bool ( how they actually do it is implementation dependent )
You can check cppreference to see the extent of flexibility standards allow for it đ
https://en.cppreference.com/w/cpp/container/vector_bool
The perticular case you are experiencing on your perticular implementation ( gcc ) here is when the elements are not conventionally stored but are rather stored such that each element requires a single bit ( rather than a byte ) and class std::vector<bool>::reference is exposed as a method of accessing individual bits, so operator[ ] doesn't return a reference ( &bool ) but a temporary value instead ( which due to obvious reasons is not allowed to bind to an lvalue reference )
+ 1
An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.
Ex& rEx = Ex(); // Error!
Ex&& rEx = Ex(); // Ok
Rvalue references can be used to extend the lifetimes of temporary objects (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them
#include <iostream>
#include <string> Â
int main() {
std::string s1 = "Test";
// std::string&& r1 = s1;
// error: can't bind to lvalue  const
std::string& r2 = s1 + s1; // okay: lvalue reference to const extends lifetime
// r2 += "Test";
// error: can't modify through reference to const Â
std::string&& r3 = s1 + s1; // okay: rvalue reference extends lifetime
r3 += "Test"; // okay: can modify through reference to non-const
std::cout << r3 << '\n'; }
you can learn more at
https://en.cppreference.com/w/cpp/language/reference
+ 1
https://code.sololearn.com/csBOra8H2329/?ref=app
+ 1
Edward Finkelstein I think Arsenic has done a great job at explaining the first case. When it comes to vector<bool>, its access operators in gcc return a temporary object of type std::vector<bool>::reference which cannot be attached to an lvalue reference.(Try replacing 'bool' with 'vector<bool>::reference' to convince yourself that an actual object is what is being returned and not a bool).
For the next two cases, I think what's happening is quite obvious. The range-based for loop returns an lvalue on each iteration, which can only be assigned to an lvalue reference.
The last case seems strange because of the way the 'auto' keyword works. I'm not going to try and explain how auto works since it's a slightly more advanced topic and there are a ton of good resources out there
But basically auto works in a similar way to how the template type resolution works.
The 'auto&& i' in the first range-based for loop behaves like a template function having a universal reference.
+ 1
[Cont.]
as its parameter e.g.
template<typename T>
void f(T&& arg);
Such a function can receive both rvalue and lvalue reference arguments.
The 'auto& i' in the second range-based for loop behaves like a template function having an lvalue reference as it's parameter. e.g
template<typename T>
void f(T& arg);
Such a function can only receive an lvalue reference as it's arguments. Since we have already established that access operators of all vector types except vector<bool> return an lvalue, the object returned on each and every iteration can be assigned to the the lvalue reference i without issues.