TITLE: Thoughts on references to temporaries and lvalues SE = Stephen G. Edwards JS = John Max Skaller , 13 Apr 93 [SE] ........................................................................ I'm a little confused about the rules for references to temporary objects. [JS] ........................................................................ No, you are not confused :-) C++ is confused. [SE] ........................................................................ Why is it that given class Thing { public: Thing(); ~Thing(); void f(); // note: non-const member function }; extern Thing ReturnThing(); my 3.0-compatible compiler will let me do this ReturnThing().f(); // call non-const function on returned temporary but warns me about this Thing& thing = ReturnThing(); // "warning: initializer for non-const ref thing.f(); // not an lvalue (anachronism)" The warning makes sense if you apply section 8.4.3 of the ARM, which says that only a const reference could be initialized in this case. But what's the point in enforcing that the reference be const, especially if I can just directly call any function I want on the returned value of the function? Isn't that value also considered a temporary? Or am I confusing my lvalues and rvalues here? [JS] ........................................................................ This very issue is a hot topic for the committee. Your analysis is spot on, in my often not very humble opinion. Unfortunately, the ARM and current working draft standard are both inconsistent and incomplete. What would you make of this: const Thing ReturnConstThing(); Does it mean anything? How about Thing().f(); What is an lvalue? Is it in any way different from a reference? Is an expression of class value an lvalue? Surely it must be, because any 'value' can be bound to a const T&, otherwise it couldn't be passed as an argument to anything .. in particular, it couldnt be copied by a copy constructor T::T(const T&) but if a value can be so bound, then for a class class X { const X* operator&()const {return this}; }; it is always possible to take the address: &(a+b) of any class valued expression, and every such expression must represent an object and so is an lvalue. You can argue that the standard & operator is different to the user defined one, but this would be very nasty that the standard operator could never be implemented by an equivalent user defined function .. and the 'standard' behaviour could always be defeated anyhow. But if we can take the address of any class object, then we also have a major incompatibility with C: struct complex { float x,y; } complex f(); &f(); This is illegal in C because f() is not an lvalue, but in C++ it must be legal. That makes the notion of lvalue next to useless in C++, because every class expression is an lvalue ... so we have to forget about lvalues and work with the type system alone (an lvalue is just a reference .. and every class valued expression is at least a const T& for some T)