I am trying to understand basic concepts of Rvalue and Lvalue reference variable and also that how they can be converted to each other (if possible) either as function parameter of as variables and to understand the memory operations involved in them - hence I cerated a class with required CTors and Dtor to understand temporary obejct creation / destruction during the operation:
class A
{
public:
A() {std::cout << "CTor Called" << std::endl;}
A(const A& a) {std::cout << "Copy CTor Called" << std::endl;}
A(A&& a) {std::cout << "MOve CTor Called" << std::endl; }
void operator =(const A& a){std::cout << "operator= Called" << std::endl;}
~A() {std::cout << "DTor Called" << std::endl;}
void Show(){std::cout << "Show Called" << std::endl;}
};
First I am able to create R & L value reference variables:
A a;
A& a1 = a;
const A& a2 = A(); // Lvalue using Rvalue
//But I am unable to create R refererence variable using an L value variable
A&& ra = a; // Does not work
A&& ra = A(); // works
So is it that R value reference variables can only be created by R values unlike L values which can be ceated using an R value
Now I wrote up below templates:
template <class T> void fooNoRef(T tmp){tmp.Show();}
template <class T> void fooLRef(T& tmp){tmp.Show();}
template <class T> void fooRRef(T&& tmp){tmp.Show();}
But I am unable to call fooRRef
function template using R value reference variable:
int main()
{
A a;
A& a1 = a;
const A& a2 = A();
A&& ra = A();
std::cout << "Calling fooNoRef Template Function" << std::endl;
fooNoRef<A>(a);
std::cout << "Calling fooLRef Template Function" << std::endl;
fooLRef<A>(a);
std::cout << "Calling fooRRef Template Function With Lvalue" << std::endl;
fooRRef<A>(ra); // Does not works??
fooRRef<A>(A());
}
So what are the concept of R and L reference variable and how to use them?
But I am unable to call
fooRRef
function template using R value reference variable:
You're confusing with types and value categories. As a named variable, ra
is an lvalue and then can't be bound to rvalue-reference.
(emphasis mine)
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
The following expressions are lvalue expressions:
- the name of a variable, a function
, a template parameter object (since C++20)
, or a data member, regardless of type, such asstd::cin
orstd::endl
. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
On the other hand, it could be bound to lvalue-reference, e.g.
fooLRef<A>(ra); // works
You can also convert it to rvalue explicitly by std::move
, e.g.
fooRRef<A>(std::move(ra)); // works
Names of rvalue reference variables are lvalues and have to be converted to xvalues to be bound to the function overloads that accept rvalue reference parameters, which is why move constructors and move assignment operators typically use
std::move
: