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&
)?
A reference (
T&
orT&&
) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references:vector<T&>
is ill formed and generates a compilation error.A
std::reference_wrapper
on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.std::ref
is a standard function that returns astd::reference_wrapper
on its argument. In the same idea,std::cref
returnsstd::reference_wrapper
to a const reference.One interesting property of a
std::reference_wrapper
, is that it has anoperator T& () const noexcept;
. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:operator T& () const noexcept;
, it can be used anywhere you could use a reference, because it will be automatically converted to it.Well
ref
constructs an object of the appropriatereference_wrapper
type to hold a reference to an object. Which means when you apply:This returns a
reference_wrapper
and not a direct reference tox
(ieT&
). Thisreference_wrapper
(ier
) instead holdsT&
.A
reference_wrapper
is very useful when you want to emulate areference
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 (sayx
), theny
andx
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:However this is legal:
Talking about your problem with
cout << is_same<T&,decltype(r)>::value;
, the solution is:Let me show you a program:
See here we get to know three things:
A
reference_wrapper
object (herer
) can be used to create an array of references which was not possible withT&
.r
actually acts like a real reference (see howr.get()=70
changed the value ofy
).r
is not same asT&
butr.get()
is. This means thatr
holdsT&
ie as its name suggests is a wrapper around a referenceT&
.I hope this answer is more than enough to explain your doubts.
std::reference_wrapper
is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.For example,
std::bind
can take in thestd::ref()
to something, transmit it by value, and unpacks it back into a reference later on.This snippet outputs :
The value of
i
has been stored (taken by value) intof1
at the point it was initialized, butf2
has kept anstd::reference_wrapper
by value, and thus behaves like it took in anint&
.