The reasoning is that * and + are operators that return constants. a*b is a function |
This statement is not quite correct. When you assign to a variable, e.g.
c = a*b;
then operator= is being passed a anonymous temporary value, known as an rvalue, which is the result of the expression evaluated on the right (here a call to operator* to evaluate a*b). This result is not (necessarily) const.
And
normal reference function parameters cannot accept rvalues.
A
normal reference needs an lvalue, which is something which has a lifetime longer than the expression it appears in. (The names lvalue and rvalue started off life meaning things that could appear on the left hand or right hand side of an expression, but that's not how they're defined these days. See below...)
Edit: I think my attempt at explaining the origin of lvalue and rvalue is a bit of a failure. See references below.
I say
normal here as C++11 introduced rvalue references, which have two &s, e.g. int&& is an rvalue reference to an int. If you alter tryout()'s signature to use one for its 3rd parameter, e.g.
void tryout(int, char, int&&, float&);
then
tryout(a,c,a*b,y);
will compile OK (though it's not necessarily the right thing to do!)
See below if you want further detail.
Andy
Try it out!
To see what's up in more detail try compiling the code!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
#include <iostream>
using namespace std;
void tryout(int, char, int&, float&);
int main()
{
int a=4, b=0;
float y=3.1415f;
char c='?';
tryout(a,c,a*b,y);
return 0;
}
// stub - does nothing except resolve linkage
void tryout(int, char, int&&, float&)
{
}
|
GCC makes two complaints:
.../main.cpp:12:17: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int' |
.../main.cpp:4:6: error: in passing argument 3 of 'void tryout(int, char, int&, float&)' |
So you can see that it doesn't like the fact that an rvalue is being passed as the 3rd parameter.
So what is
an rvalue?
A quick google later ("what's an rvalue?")...
An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it. |
From: Lvalues and Rvalues
https://msdn.microsoft.com/en-us/library/f90831hc.aspx
And for rather more detail "see values and rvalues in C++98/03" section here:
Rvalue References: C++0x Features in VC10, Part 2
http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
Test with rvalue
In this code I've swapped the signature to:
void tryout(int i, char c, int&& ri, float& rf);
and it compiles OK with (if you use a C++11 compliant compiler!):
tryout(a,c,a*b,y);
But note that when you run the code, which changes the int passed to the third parameter, it is just pointlessly changing the temporary value (rvalue) returned by a+b which cannot be accessed later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#include <iostream>
#include <ctype.h>
using namespace std;
void tryout(int i, char c, int&& ri, float& rf); // with rvalue reference
int main()
{
int a=4, b=0;
float y=3.1415f;
char c='x';
cout << "[before]\n"
<< "a = " << a << "\n"
<< "b = " << b << "\n"
<< "j = " << y << "\n"
<< "c = " << c << "\n"
<< "\n";
cout << "[call tryout]\n";
cout << "tryout(a,c,a*b,y);\n"
<< "\n";
tryout(a,c,a*b,y);
cout << "\n";
cout << "[after]\n"
<< "a = " << a << "\n"
<< "b = " << b << "\n"
<< "j = " << y << "\n"
<< "c = " << c << "\n"
<< "\n";
return 0;
}
// stub - does nothing except resolve linkage
void tryout(int i, char c, int&& ri, float& rf)
{
cout << "* * * ENTER TRYOUT * * *\n";
cout << "[starting values]\n"
<< "i = " << i << "\n"
<< "c = " << c << "\n"
<< "ri = " << ri << "\n"
<< "rf = " << rf << "\n"
<< "\n";
cout << "* * * CHANGE ALL VALUE * * *\n";
cout << "i = " << -i << "\n";
i = -i;
char temp = '?';
if(isalpha(c))
temp = static_cast<char>(toupper(c));
cout << "c = " << temp << "\n";
c = temp;
cout << "ri = " << i << "\n";
ri = i;
cout << "rf = " << (rf * rf) << "\n";
rf = (rf * rf);
cout << "\n";
cout << "[ending values]\n"
<< "i = " << i << "\n"
<< "c = " << c << "\n"
<< "ri = " << ri << "\n"
<< "rf = " << rf << "\n"
<< "\n";
cout << "* * * LEAVE TRYOUT * * *\n";
}
|
[before]
a = 4
b = 0
j = 3.1415
c = x
[call tryout]
tryout(a,c,a*b,y);
* * * ENTER TRYOUT * * *
[starting values]
i = 4
c = x
ri = 0
rf = 3.1415
* * * CHANGE ALL VALUE * * *
i = -4
c = X
ri = -4
rf = 9.86902
[ending values]
i = -4
c = X
ri = -4
rf = 9.86902
* * * LEAVE TRYOUT * * *
[after]
a = 4
b = 0
j = 9.86902
c = x |