tags:

views:

148

answers:

4

I have a class whose name is YourClass. And my problem is WHY compiler do NOT generate an error for following code?

YourClass AMethod(){ return YourClass();}
AMethod() = YourClass();

[In this case IN MY OPINION AMethod just return a value (I mean it do not have a l-value).]

EDIT: If I can do that above why I can not do following

int AMethod(){ return a;}
AMethod() = 5;
+2  A: 

EDIT1: I think I miss understood the question first time.

The standard says: 3.10 Lvalues and rvalues

The result of calling a function that does not return a reference is an rvalue. User defined operators are functions, and whether such operators expect or yield lvalues is determined by their parameter and return types.

The standard says nothing in this paragraph, except that user-defined types and primitive types are the same. If the return of a function is not a reference, then it is not an l-value. There is however an interesting commentary on the same page:

47) Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues.

So basically in your example:

AMethod() = YourClass();

AMethod returns a user-defined type on which the function:

AMethod().operator=(YourClass());

is executed. Still, it is not an l-value. In fact, you could have empty statements in C++, or statement that consist of an r-value only!:

5;;; // correct C++ code!


EDIT2:

Consider this example:

if( &(YourClass() + YourClass()) == &YourClass() )
{
....
}

The expression &(YourClass() + YourClass()) must yield an l-value so the whole expression becomes correct. It compiles fine on VC but it gives this little warning:

warning C4238: nonstandard extension used : class rvalue used as lvalue

Obviously the above line was wrong by C++ standards but VC just allows it!


Because you asked it so. First, a fresh instance of YourClass is returned by AMethod. Then, it is assigned another fresh instance. Of course in C++ you can say what ever you want. So, to prevent the assignment statement, just return const YourClass. In this case, the object becomes "readable" only:

const YourClass AMethod(){ return YourClass();}

This is the same in case you are overloading binary operators. For example, if you overload operator+ for a class, then you can do with const or without it.

// '+' operator is defined as a friend operator not a member.
friend YourClass operator+(const YourClass& lhs, const YourClass& rhs)
{
...
}

If you did it that way, you could have meaningless statement like the following:

(a + b) = c;

Where the expression (a + b) is not useful because it represents only a value, not a variable we control, it produces a temp variable.

AraK
Aw, you beat me by 6 seconds :|
GMan
Seems like a good answer, but when I tried the example code I got errors. And I'm quite surprised that the compiler wouldn't at least generate a warning at using a temporary for an lvalue.
Mark Ransom
@Mark Thanks. Do you mean the second example? I assumed that the operator is defined as a friend operator not a member. I'll edit the post to clarify that :)
AraK
I meant the example posted in the original question gave an error. Sorry I didn't make that clear. It makes me wonder how relevant the question is though, and whether your answer makes sense.
Mark Ransom
@Mark: This `struct YourClass { YourClass} AMethod(){ return YourClass();} int main() { AMethod() = YourClass(); }` compiles just fine for me.
sbi
A good answer, though it's also worth explicitly spelling out the assignment as what it really is - i.e. `AMethod().operator=(YourClass())`. IMO, this makes it very clear what's actually going on right away.
Pavel Minaev
Thanks Pavel, nice addition.
AraK
+2  A: 

AMethod returns an rvalue. In C++ you can call member functions, even modifying member functions, on an rvalue of user-defined type. And sometimes this is just what you want.

os.get_disk_accessor(0).wipe(); // wipe() might not be a const member function

However, you can not invoke operations on rvalues of built-in types:

int f();
f() = 5; // won't compile
++f();   // won't either
sbi
A: 

The expression

AMethod()

creates and returns a class object, and the expression

AMethod() = YourClass();

creates and assigns a second class object to the first object.

Loadmaster
However, the interesting this is that, if your replace `YourClass` with a built-in, this doesn't work. See my reply: http://stackoverflow.com/questions/1506727/1506893#1506893
sbi
A: 

I think that 1'st version compiled because YourClass have a default constructor, destructor, copy constructor and assignment operator which called AMethod() = YourClass();. int AMethod(){ return a;} AMethod() = 5; This code doesn't compile because there is not a rvalue.

Davit Siradeghyan