1

Suppose that i have a class named Foo with copy-assignment operators, i thought that this:

Foo() = Foo();

wasn't permitted, because i thought (sorry, again) that Foo() was an rvalue (so i can't assign to it), being a temporary object. Obviously, i tried to make this code work, and it worked properly, displaying some string to verify that my programm correctly uses the copy-assignment operator.

Am I wrong? Or is this a sort of bug? What use can have?

Pipo
  • 185
  • 8
  • Related: http://stackoverflow.com/questions/16995463/should-implicitly-generated-assignment-operators-be-ref-qualified – Oktalist Aug 19 '14 at 22:57

4 Answers4

9

Foo() is an rvalue, that's for sure.

But the expression Foo() = Foo() is equivalent to Foo().operator=(Foo()). Even though Foo() is an rvalue, you are still allowed to call a member function on it, even a member function that modifies it.

Of course, an rvalue of fundamental type isn't allowed on the left-hand side of an assignment. Fundamental types are treated differently from user-defined types in this regard.

This is why, in C++, "lvalue" shouldn't be defined as "something that can appear on the left hand side of an assignment"!

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
1

Foo has an overloaded copy-assignment/move-assignment operator. Either one was implicitly provided or you wrote it yourself. Either way, because Foo() is an instance it is able to access member function operators just as well as regular member functions.

David G
  • 94,763
  • 41
  • 167
  • 253
1

You're right that the = operator normally requires that its left operand be an lvalue. However, when operators are applied to types for which they have been overloaded, they are transformed into function calls. Your code is equivalent to:

Foo().operator=(Foo())

The . operator will happily accept an rvalue as its left operand.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
0

An object cannot be "rvalue" or "lvalue". The concept if different kind of values (lvalue, rvalue, xvalue, prvalue, etc.) are applicable to expressions, used to access object, not to objects themselves.

In your case functional cast expression Foo() indeed produces a temporary object as an rvalue. However, inside any method of that temporary object you can use expression *this, which will expose the very same temporary object as an lvalue. In other words, the popular belief that temporary objects are rvalues is patently incorrect. It is always a matter of what kind of expression you use to access the object.

There's nothing unusual in the fact that you can use it on the left-hand side of an assignment. The "lvalue" requirement applies to the built-in assignment operator only. For overloaded assignment operator there's no such requirement and there's never been one. And in your case you are using an overloaded operator.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765