The message says that you are trying to assign an expression that is not an lvalue value. For built-in types, you can only assign lvalues โโ(where the name occurs: lvalue = the value that can be on the left side of the assignment operator, while rvalue = the value that should be on the right side of the assignment operator).
So what is lvalue or rvalue? Consider the following code:
int a; a = 3;
In this assignment, a
is the value of lvalue (if it werenโt, the compiler will complain). That is, the expression a
refers to an object that can be modified. On the other hand, 3
is the value of r, that is, basically the value. Of course you cannot assign 3
; the compiler will complain about 3=a;
with the same message you received in your code.
So, in a first approximation, lvalue denotes an object, and rvalue denotes a value. Note that this is also true for form assignment.
a = b;
where b
also a variable. Here the so-called conversion of lvalue to rvalue occurs: not the object b
assigned, but its current value.
Now consider the following case:
int f(); f() = 3;
Here you can argue that the function f
returns an object (if you use a specific user type, you can even see its construction / destruction). But the compiler is still complaining about your message. Why?
Well, even if you think f
returns an object, it is a temporary object that will disappear immediately. Therefore, it makes no sense to assign a value, because after that you can do nothing with it.
Therefore, here is the second rule:
Whenever there is an expression that creates a temporary object, C ++ defines this expression as an rvalue.
And now we move on to the definition of MyVector::at()
, which you did not show, but which, according to the error message, looks something like this:
template<typename T> T MyVector<T>::at(int i) { return data[i]; }
This is essentially the same kind as f
above, since it also returns T
(an employee*
in your case). This is why the compiler complains.
And this complaint is useful: even if the compiler does not complain, the code will not do what you almost certainly planned. The return
returns a copy of the data[i]
object. Thus, if the command payment.at(i)=NULL;
was compiled, what would actually happen, would be the following:
- The internal
data[i]
object (or, nevertheless, you called it in the code) is copied and a temporary copy is returned. - The statement assigns this temporary copy, but the original object in
MyVector
does not change. - The temporary copy is destroyed, leaving no trace of your destination.
This is almost certainly not what you wanted. You want to change the internal object. To do this, you need to return a link to this object. The reference refers to the object that was initialized, instead of making a copy. Accordingly, a link, even when it returns, is an lvalue value (since C ++ 11 contains a second type of link that behaves differently, but we donโt need to take care here). Then your fixed function reads
template<typename T> T& MyVector<T>::at(int i) { return data[i]; }
and with this definition payment.at(i)=NULL;
not only compiles, but also does what you want: change the internally stored i
pointer in payment
to NULL
.