I have some questions regarding this program:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
The output is:
false
I want to know, if std::ref
doesn't return the reference of an object, then what does it do? Basically, what is the difference between:
T x;
auto r = ref(x);
and
T x;
T &y = x;
Also, I want to know why does this difference exist? Why do we need std::ref
or std::reference_wrapper
when we have references (i.e. T&
)?
Well ref
constructs an object of the appropriate reference_wrapper
type to hold a reference to an object. Which means when you apply:
auto r = ref(x);
This returns a reference_wrapper
and not a direct reference to x
(ie T&
). This reference_wrapper
(ie r
) instead holds T&
.
A reference_wrapper
is very useful when you want to emulate a reference
of an object which can be copied (it is both copy-constructible and copy-assignable).
In C++, once you create a reference (say y
) to an object (say x
), then y
and x
share the same base address. Furthermore, y
cannot refer to any other object. Also you cannot create an array of references ie code like this will throw an error:
#include <iostream>
using namespace std;
int main()
{
int x=5, y=7, z=8;
int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references
return 0;
}
However this is legal:
#include <iostream>
#include <functional> // for reference_wrapper
using namespace std;
int main()
{
int x=5, y=7, z=8;
reference_wrapper<int> arr[] {x,y,z};
for (auto a: arr)
cout << a << " ";
return 0;
}
/* OUTPUT:
5 7 8
*/
Talking about your problem with cout << is_same<T&,decltype(r)>::value;
, the solution is:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
Let me show you a program:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
int main()
{
cout << boolalpha;
int x=5, y=7;
reference_wrapper<int> r=x; // or auto r = ref(x);
cout << is_same<int&, decltype(r.get())>::value << "\n";
cout << (&x==&r.get()) << "\n";
r=y;
cout << (&y==&r.get()) << "\n";
r.get()=70;
cout << y;
return 0;
}
/* Ouput:
true
true
true
70
*/
See here we get to know three things:
A reference_wrapper
object (here r
) can be used to create an array of references which was not possible with T&
.
r
actually acts like a real reference (see how r.get()=70
changed the value of y
).
r
is not same as T&
but r.get()
is. This means that r
holds T&
ie as its name suggests is a wrapper around a reference T&
.
I hope this answer is more than enough to explain your doubts.