I am trying to make a struct Fraction. I have defined constructors and operator>> and operator<< for it, and that works correctly.
When I was defining operator+ I got the following error message with my code:
cannot bind non-const lvalue reference of type 'Fraction&' to an rvalue of type 'Fraction'
This is my code:
struct Fraction
{
int a;
int b;
Fraction()
{
a = 0;
b = 1;
}
Fraction(Fraction& f)
{
a = f.a;
b = f.b;
}
Fraction(int x, int y)
{
a = x;
b = y;
if (b < 0)
{
b *= -1;
a *= -1;
}
}
};
istream & operator>>(istream & in, Fraction & f)
{
...
return in;
}
ostream & operator<<(ostream & out, Fraction f)
{
if (f.b == 1 || f.a == 0)
out << f.a;
else
out << f.a << "/" << f.b;
return out;
}
Fraction operator+(Fraction f1, Fraction f2)
{
Fraction f((f1.a * f2.b) + (f2.a * f1.b), f1.b * f2.b);
return f;
}
int main()
{
Fraction a, b;
cin >> a >> b;
cout << a + b << endl;
}
If I change the last part and write this, it works correctly:
int main()
{
Fraction a, b, c;
cin >> a >> b;
c = a + b;
cout << c << endl;
}
I don't understand why this happens at all, and I would like to figure it out.
I'm just a beginner and I understand that the question may be stupid and obvious. Could you please explain what lvalue and rvalue are, how to use them, and how to correct the code? I have already read some articles about this, but I still don't understand how this all relates to my situation.
An lvalue (historically, something that appears on the left-side of an assignment) generally refers to anything that has a name.
An rvalue (historically, something that appears on the right-hand side of an assignment) generally refers to anything that is temporary.
See Value Categories on cppreference.com for more specific details.
A reference to a non-const object requires a pre-existing object to bind to, it cannot bind to a temporary object. That is what the compiler error is complaining about. A reference to a const object, on the other hand, can bind to a temporary object.
In your first example, the expression
cout << a + breturns a temporary object fromoperator+and then passes it as-is to youroperator<<. Youroperator<<is taking in aFractionobject by value for itsfparameter, so anything that is passed in to it requires the compiler to create a newFractionobject forf. Since you are passing in a (temporary)Fractionobject as input, theFractioncopy constructor gets called, but your copy constructor does not accept a temporary object as input, hence the compiler error.In your second example, you are assigning the temporary
Fractionobject to a local variable first, and then theFractioncopy constructor is able to bind itsfparameter to that object when the compiler is constructing thefparameter ofoperator<<.To fix this, you need to either:
omit your copy constructor altogether and let the compiler generate a default copy constructor for you (just as you are doing for the default compiler-generated assignment
operator=). The compiler will produce the correct code in this example.change your copy constructor to take in a reference to a const object instead, eg:
Either way, your
operator<<andoperator+should take in theirFractioninputs as const references, eg: