I was trying out the std::reference_wrapper
with the following snippet
int a = 42, b = 52;
std::tuple<std::reference_wrapper<int>> t = std::make_tuple(std::ref(a));
std::get<0>(t) = b;
std::cout << "t[0] = " << std::get<0>(t) << ", a = " << a << ", b = " << b
<< std::endl;
The output is t[0] = 52, a = 42, b = 52
, which not surprising.
However, if I just use auto
for t
, namely
int a = 42, b = 52;
auto t = std::make_tuple(std::ref(a));
std::get<0>(t) = b;
std::cout << "t[0] = " << std::get<0>(t) << ", a = " << a << ", b = " << b
<< std::endl;
Then I got t[0] = 52, a = 52, b = 52
Looks like the type becomes int&
. Then I have some questions:
std::ref
gives us std::reference_wrapper
rather than &
?&
and why it is different from std::reference_wrapper
.std::reference_wrapper
, std::get<0>(t) = 52;
does not compile. (While in the case of &
it does). the error is "calling a private constructor of class 'std::__1::reference_wrapper'". Could someone explain that in more detail?Thanks!!
- I thought std::ref gives us std::reference_wrapper rather than &?
That's not a question, but you thought correctly.
- How I should explain the case of & and why it is different from std::reference_wrapper.
When a std::reference_wrapper
argument passed to std::make_tuple
, the resulting tuple will have a reference member rather than a reference wrapper.
The difference in behaviour is because when you assign a reference, you modify the referred object while when you assign a reference wrapper, you instead rebind the wrapper to refer to another object and don't modify the referred object.
I also noticed that, in the case of std::reference_wrapper, std::get<0>(t) = 52; does not compile. (While in the case of & it does). the error is "calling a private constructor of class 'std::__1::reference_wrapper'". Could someone explain that in more detail?
std::reference_wrapper
doesn't have an assignment operator for the referred type. It only has assignment operator for another reference wrapper. std::reference_wrapper
has an implicitly converting constructor that accepts an lvalue, but not one that accepts an rvalue.
That is why you can assign b
which is an lvalue, but cannot assign 52 which is a prvalue. This is a good thing because the lifetime of the temporary object cannot be extended by the reference wrapper.