Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!uunet!shelby!agate!pasteur!galileo.berkeley.edu!jbuck From: jbuck@galileo.berkeley.edu (Joe Buck) Newsgroups: comp.lang.c++ Subject: Re: Distinguishing lvalue/rvalue operator[] Message-ID: <11646@pasteur.Berkeley.EDU> Date: 4 Mar 91 05:02:50 GMT References: <1991Mar3.202134.17812@mathcs.sjsu.edu> Sender: news@pasteur.Berkeley.EDU Reply-To: jbuck@galileo.berkeley.edu (Joe Buck) Lines: 65 In article <1991Mar3.202134.17812@mathcs.sjsu.edu>, horstman@mathcs.sjsu.edu (Cay Horstmann) writes: |> I recently suggested to distinguish lvalue and rvalue operator[] by |> passing in an additional int for one of them, just like pre- and |> post operator++ are distinguished in 2.1. Joe Buck suggested this is |> unnecessary--one can have operator[] return an access class with |> X& Access::operator=( X& ); // for lvalue usage |> Access::operator X(); // for rvalue usage |> I just tried this out and it broke my code right away. The line |> a[i].print(); |> didn't compile--print() is not a member function of Access! Joe's suggestion |> works fine for non-class types because the type conversion Access->X will |> be executed, except before . and ->. The helper class, Access in your code, is an example of a "smart reference". For smart pointers, -> can be overloaded to do the right thing. That leaves as the only hole the fact that "." cannot be redefined for smart references. Now this is an extension I would support, since it is clean and makes the language more orthogonal. Semantically, what is being returned by [] is a reference (though in some cases it needs to be a tricky one). |> with a disgusting scenario where the overloading resolution rules give |> unexpected results when one of the arguments of a function f with multiple |> versions is f( ... a[i] ... ). There should be no unexpected results in this case, because there is one and only one type conversion operator for class Access. The only problem that cannot be worked around is the . operator. |> I repeat my call for two versions of this operator. William Miller had three |> arguments against it. |> (1) There is an alternate solution. |> I hope my argument against this is conclusive. It shows a problem with it, but other than that problem (which can be solved for the previously proposed extension, smart references to complement smart pointers), it works well and is used extensively in class libraries. You cannot say a[i].print() but you can say X(a[i]).print(), which I will grant is ugly. |> (2) It breaks existing code |> Isn't it possible to map both lvalue and rvalue [] to the same |> operator[](int) if an operator[](int,int) is not present? |> (3) It makes operator[] special. |> I agree. On the other hand, it may well reasonable to have some operators |> special. The assignment operator= is clearly special. So is operator->. |> In fact, it probably makes sense to have both unary operator* and |> operator[] lvalue/rvalue aware because their C analogs are. In contrast, |> operator++ shouldn't have this awareness because the C analog doesn't |> either. |> Two comments. The problem I encountered could be solved by overloading |> operator. . <- the first is a dot operator, the second a sentence terminator. |> I realize that the trick of supplying a second int argument isn't going to |> work for distinguishing lvalue/rvalue occurrences of unary operator*. All the problems you describe can be eliminated by overloading operator. . The semantics are exactly analogous to overloading operator-> . You have shown a lack in the language, but the solution you propose is weaker and uglier than a "smart reference" solution, which also gets rid of the problems with unary *. -- Joe Buck jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck