Explain me, please, how it works? Why double && works for lvalue and rvalue? And why const double && don't work for lvalue?
template <typename U>
void function(U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45); //error
}
error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’ function(45); ////////////////////////////////////////////////
template <typename U>
void function(const U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////////////
template <typename U>
void function(U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////////////
template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1); // error
function(45);
}
error: cannot bind ‘int’ lvalue to ‘const int&&’ function(var1);
double &&
does not work for lvalues. However, you don't have double &&
in your code, you have U &&
for a deduced U
. That is special syntax for a so-called forwarding reference.
There's a special rule in C++ template deduction rules which says that when the parameter type is T&&
where T
is a deduced type, and the argument is an lvalue of type X
, then X&
is used instead of X
for type deduction.
In your case, this means U
is deduced to be int&
, so the type of parameter var
is collapsed from "int& &&
" into int &
.
You can learn more about this mechanism by searching for terms such as "forwarding reference" (historically called "universal reference") or "perfect forwarding."