I have an interesting example to understand lvalue reference, rvalue reference, and std::forward. Maybe it will be a useful example for a deep understating concept.
void foo(int&& a){
cout<<"foo&&"<<endl;
}
void foo(int& a){
cout<<"foo&"<<endl;
}
template <typename T>
void wrapper(T&& a){
cout<<"wrapperTemplate"<<endl;
foo(forward<T>(a));
};
int main()
{
double&& a=5;
double& t=a;
wrapper(t);
}
The output is:
wrapperTemplate
foo&&
CodePudding user response:
You can't call the lvalue reference version, as t
is a double
and foo()
expects an int
. And you can't bind the temporary generated by the implict cast from double
to int
to an lvalue reference. The temporary is an rvalue, so can be used to call the rvalue overload.
The fact that a
is an rvalue reference doesn't change the result:
double a=5;
double& t=a;
wrapper(t);
still prints:
wrapperTemplate
foo&&
https://godbolt.org/z/89T7Wzc8e
If the types do match, the lvalue reference function is called:
int a=5;
int& t=a;
wrapper(t);
prints:
wrapperTemplate
foo&
https://godbolt.org/z/chnzaKhGf
If you use std::move()
, you get back to the rvalue reference version:
int a=5;
int& t=a;
wrapper(std::move(t));
prints:
wrapperTemplate
foo&&
https://godbolt.org/z/68KPYrhYP
Removing wrapper
also doesn't change the behaviour:
double a=5;
foo(a);
int b=5;
foo(b);
foo(std::move(b));
prints:
foo&&
foo&
foo&&