From this link, it says that
Objects, references, functions including function template specializations, and expressions have a property called type
<
Based on this each function call is an expression. Each argument passed to the function is also an expression.
Therefore, when you make a call to SumFunc(rf_int);
you create an expression from the single rf_int
variable.
ISO/IEC 14882 (c++14 standard) states that "The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression."
Thus, the rf_int
expression will be of type int.
This comment (you mention it before) is about type conversion error.
To illustrate my explanation, I have prepared a more complex, but (hopefully) more understandable example. This example is about why we need rvalue refernce type and how to use it correctly.
class Obj {
int* pvalue;
public:
Obj(int m) {
pvalue = new int[100];
for(int i = 0; i < 100; i++)
pvalue[i] = m + i;
}
Obj(Obj& o) { // copy constructor
pvalue = new int[100];
for(int i = 0; i < 100; i++)
pvalue[i] = o.pvalue[i];
}
Obj(Obj&& o) { // move constructor
for(int i = 0; i < 100; i++)
pvalue = o.pvalue;
o.pvalue = nullptr;
}
// ...
};
Example 1
Obj obj1(3);
Obj obj2(obj1); // copy constructor
Obj obj3(std::move(obj1)); // move constructor
Obj obj4(Obj(3)); // move constructor
Line #1 - obj1 created.
Line #2 - obj2 created as a copy of obj1
Line #3 - obj3 created by moving value of obj1 to the obj3; obj1 loose it's value
Line #4 - temporary object created by Obj(3); obj4 created by moving value of temporary object to obj4; temporary object loose it's value
I think we have no real need of int&&
but Obj&&
can be very useful. Especially in the line #4.
Example 2 with my (simplified) interpretation of compiler errors
void SomeFunc0(Obj arg) {};
void SomeFunc1(Obj& arg) {};
void SomeFunc2(Obj&& arg) {};
int main()
{
Obj obj1(3); // object
Obj& obj2 = obj1; // reference to the object
Obj&& obj3 = Obj(3); // reference to the temporary object with extened lifetime
SomeFunc0(obj1); // ok - new object created from Obj
SomeFunc0(obj2); // ok - new object created from Obj&
SomeFunc0(obj3); // ok - new object created from Obj&&
SomeFunc0(Obj(3)); // ok - new object created from temporary object
SomeFunc0(std::move(obj1)); // ok - new object created from temporary object
SomeFunc0(std::move(obj2)); // ok - new object created from temporary object
SomeFunc0(std::move(obj3)); // ok - new object created from temporary object
SomeFunc1(obj1); // ok - reference to obj1 passed
SomeFunc1(obj2); // ok - reference to obj1 passed
SomeFunc1(obj3); // ok - reference to temp. obj. passed
SomeFunc1(Obj(3)); // error - lifetime of the temp. obj. too short
SomeFunc1(std::move(obj1)); // error - lifetime of the temp. obj. too short
SomeFunc1(std::move(obj2)); // error - lifetime of the temp. obj. too short
SomeFunc1(std::move(obj3)); // error - lifetime of the temp. obj. too short
SomeFunc2(obj1); // error - temporary object required
SomeFunc2(obj2); // error - temporary object required
SomeFunc2(obj3); // error - lifetime of the temp. obj. too long
SomeFunc2(Obj(3)); // ok
SomeFunc2(std::move(obj1)); // ok
SomeFunc2(std::move(obj2)); // ok
SomeFunc2(std::move(obj3)); // ok
return 0;
}