From: jimad@microsoft.com (Jim Adcock)
Subject: Re: return type of operator=
Date: 05 Nov 92 19:02:57 GMT
Organization: Microsoft Corporation

In article <1992Nov4.051914.25983@en.ecn.purdue.edu> davisonj@en.ecn.purdue.edu (John M Davison) writes:
|In article <1992Nov03.195240.14360@microsoft.com> jimad@microsoft.com (Jim Adcock) writes:
|>In article <1992Oct31.025229.6520@cs.brown.edu> sdm@cs.brown.edu (Scott Meyers) writes:
|>|Is the return type of operator= an lvalue?  
|>
|>No.
|
|        Jim is mistaken; the built-in types return an lvalue in C++ (except for
|bit-field assignment, which I don't know about offhand).
|
|>|In particular, if a, b, and c are of built-in type, is this legal?
|>|
|>|    (a = b) = c;
|>
|>No, it is an error.  If (a = b) were an lvalue the same
|>as "a" then "a" would be being accessed twice for modification in one
|>expression, which in turn is an unconstrained error.  
|
|        It is not an error.  ((a=b)=c) is equivalent to (a=c), except for side
|effects, of course.

I continue to disagree -- with a *tiny* retraction.  The ref manual says
that (a = b) is a *value* which is a lvalue.  The ref manual DOES NOT specify
that the lvalue is a reference to a.  Thus I continue to maintain that

((a=b)=c) 

has to either NOT modify a in the outer assignment, rather instead modifying
an unnamed temporary, or alternately a is being accessed twice in one expression
for modification, which continues to be an unconstrained error.  In either
case it is certainly NOT correct to say that ((a=b)=c) is the same as (a=c)
except for side effect.  Either ((a=b)=c) is NOT the same as (a=c) or
alternately its an unconstrained error.

|>My answers are based on the ANSI-C spec
|
|        In Standard C, = returns an rvalue.  In C++, = returns an lvalue.
|
|        Stroustrup talks about this in the "Lvalues" section of "The Evolution
|of C++: 1985 to 1989".  I quote:
|
|                  "Note that the default definition of assignment of
|          an X as a call of
|
|              X& operator=(const X&)
|
|	  makes assignment of Xs produce an lvalue.  For uniformity,
|	  this rule has been extended to assignments of built-in
|	  types.  By implication, +=, -=, *=, etc.  now also produce
|	  lvalues.  So -- again by implication -- does prefix ++ and
|	  -- (but not the postfix versions of these operators).
|
|                  "In addition, the comma and ?: can also produce
|          lvalues...."

Note in none of this did the author of one of the base documents specify
*what* object the lvalue was referring to.  By continuing *not* to make
that specification the situation remains the same as in ANSI-C where accessing
a variable more than once in an expression for modification remains
ill-defined.  You may get either or both side-effects or neither or something
else entirely.

|>The "right" thing to do is to return a value, not a reference.
|>...Don't return a non-const reference.
|
|        Return a non-const reference.  C++ does it with its built-in types.

I continue to disagree.  It is extremely unlikely that any C++ programmer
is going to use that non-const reference in a legal manner.  Do them a 
favor up front and at least make it const.  

I wonder if this whole mess shouldn't be added to the list of non-modifiable 
lvalues?  Or are these issues going to be eventually clarified by adding clear
constraints to the eventual ANSI/ISO-C++ spec?
  
Newsgroups: comp.std.c++