I am new to r-values and l-values in C++. I was playing with it. I am not sure why the following code works:
class A {
public:
A() {
std::cout<<"Constructor called"<<std::endl;
}
A(const A& a) {
std::cout<<"Copy Constructor called"<<std::endl;
}
};
template<typename T>
void printA(T&& b) {
std::cout<<"Print method called"<<std::endl;
}
int main() {
// your code goes here
A a;
printA(a);
return 0;
}
but the code fails to compile, if I change printA method to the following:
void printA(A&& b)
Below is the full code:
class A {
public:
A() {
std::cout<<"Constructor called"<<std::endl;
}
A(const A& a) {
std::cout<<"Copy Constructor called"<<std::endl;
}
};
void printA(A&& b) {
std::cout<<"Print method called"<<std::endl;
}
int main() {
// your code goes here
A a;
printA(a);
return 0;
}
The compiler throws following error:
candidate function not viable: no known conversion from 'A' to 'A &&' for 1st argument
I understand we can make the above code work, by converting l-value to r-value reference using std::move
, but not sure why code I shared at the beginning of the post is working!
Can somebody tell me what I am doing wrong here? Thanks!
In this function template:
template<typename T>
void printA(T&& b) {
std::cout<<"Print method called"<<std::endl;
}
T&&
is a forwarding reference. This means it can bind to l-values, or r-values:
A a;
printA(a); // ok, l-value
printA(A{}); // ok, r-value
However, this is a regular function that takes exactly an r-value:
void printA(A&& b) {
std::cout<<"Print method called"<<std::endl;
}
and so can only be called with an r-value:
A a;
printA(a); // error, can't bind r-value to l-value
printA(A{}); // ok, r-value