3

When I try compiling following program, I get an error on l-value which makes sense. Error is: error C2106: '=' : left operand must be l-value

Code:

int main() 
{
    int a,b,c,d;
    b+c=d;
    return 0;
 }

But following code works absolutely fine when I replace integer with my own structure

struct MyStruct
{
    int val;
    MyStruct(){}
};

MyStruct operator+(MyStruct& s1, MyStruct& s2)
{
    MyStruct temp;
    return temp;
}

int main() 
{

    MyStruct a,b,c,d;
    b+c=d;
    return 0;
}

How come the second code compiles? I know I can return const from the operator+. But isn't b+c in second example a rvalue? So how come it compiles

Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
user2600393
  • 151
  • 1
  • 4

2 Answers2

2

Cory Klein has already explained here why the code compiles.

I just want to add that if you want MyStruct to behave as the ints (and othe built-in types), then add this line to MyStruct:

MyStruct& operator =(const MyStruct&) && = delete;

This tells the compiler that that everytime the operator =() is called on a MyStruct object that is an rvalue (thanks to the ref-qualifier &&) the code should not be valid because the operator =() does not exist (= delete;). Indeed, GCC 4.8.1 emmits the following:

error: use of deleted function 'MyStruct& MyStruct::operator=(const MyStruct&) &&'

b+c=d;
   ^

Update: Following the comment by Casey (many thanks).

There's one issue with adding the line above to MyStruct. It also prevents assignment to an lvalue. That is, the line below also becomes illegal:

b = c;

If you want to disable assignment to an rvalue but still allows assignment to lvalues, then instead of the line above, add this one to MyStruct:

MyStruct& operator =(const MyStruct&) & = default;

(or provide a correct implementation if the compiler generated one doesn't fit your purposes.)

Community
  • 1
  • 1
Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
  • I've been using `MyStruct& operator = (const MyStruct&) & = default;` to accomplish the same end. Can you think of any reason to favor deleting over defaulting? – Casey Jul 19 '13 at 18:58
  • @Casey: I didn't know that this would do the same. Actually your solution is superior to mine and I will update my answer. Thanks for this. – Cassio Neri Jul 19 '13 at 19:54
1

In this code:

MyStruct a,b,c,d;
b+c=d;

As you have defined the operator+() function, it returns a MyStruct. Therefore b+c, which calls the function you defined, returns a MyStruct, and then the operator=() function is called on that MyStruct, and it is passed d as an argument.

Although the temporary MyStruct is an rvalue because of its temporary nature, the code still compiles because of the reasons I explained above, and the fact that the C++ standard does not forbid calling the operator=() function on an rvalue when that rvalue is a user defined object and not an integral type.

In this code:

int a,b,c,d;
b+c=d;

b+c returns an r-value int. Having an r-value on the left side of an = operator is not C++ syntax. Either way, it wouldn't make any sense to assign a value to it, whereas calling the operator=() function on a temporary MyStruct could potentially have side effects.

Community
  • 1
  • 1
Cory Klein
  • 51,188
  • 43
  • 183
  • 243
  • If it is not C++ syntax, then howcome it compiles? Instead If I write (b+c).val = d.val this one fails – user2600393 Jul 19 '13 at 18:21
  • 1
    It does not compile, you say so yourself - it gets error code C2106. The `MyStruct` code *is* proper C++ syntax, therefore it compiles. – Cory Klein Jul 19 '13 at 18:23
  • Thanks for the clarification. I guess my basic query is why temporary Mystruct is not a r-value – user2600393 Jul 19 '13 at 18:27
  • @Cory Klein: "That temporary MyStruct is not an r-value.". Actually, the temporary is an rvalue. The issue is that rvalues of class type don't behave like rvalues of bult-in types (as you have clearly explained). – Cassio Neri Jul 19 '13 at 18:30
  • I've updated the answer with an explanation on why `MyStruct` is not an rvalue. – Cory Klein Jul 19 '13 at 18:32
  • @CassioNeri I don't doubt that what you say is true, but it does conflict with the definition in the referenced link I just added to the answer. Can you provide some point of reference to show that the temporary `MyStruct` is in fact an r-value? – Cory Klein Jul 19 '13 at 18:33
  • Okay, I've added another reference defining the `MyStruct` as an lvalue. Now I am beginning to doubt you @CassioNeri ;) – Cory Klein Jul 19 '13 at 18:35
  • @Cory Klein: The most voted answer [here](http://stackoverflow.com/questions/579421/often-used-seldom-defined-terms-lvalue) is correct for C (I guess) but C++ is different. For instance, see the answer by [Johannes Schaub - litb](http://stackoverflow.com/a/579514/1137388). In particular he says "The term "rvalue" is used for things like literals and enumerator values and for **temporaries**". – Cassio Neri Jul 19 '13 at 18:41
  • @Cory Klein: Last comment: The C++11 standard says (3.10/1): "An **rvalue** (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a **temporary object** (12.2) or subobject thereof, or a value that is not associated with an object.". – Cassio Neri Jul 19 '13 at 18:46
  • @CassioNeri Thanks for the link. I agree it makes a good argument for it being an r-value. I updated my answer, but now I'm just not really convinced either way, and I can't find anything more official than opinions of smart people on the internet. – Cory Klein Jul 19 '13 at 18:50
  • @CassioNeri Ah! Perfect, just what I was looking for. I'll update the answer. – Cory Klein Jul 19 '13 at 18:51