Topic: Return type of operator->()


Author: gjditchfield@watmsg.uwaterloo.ca (Glen Ditchfield)
Date: Mon, 1 Apr 1991 16:23:52 GMT
Raw View
There are restrictions on the allowed return type of operator->().  Where
should they be enforced?  I think they should be enforced at the call site,
not the declaration, at least when templates are involved.
   Chapter and verse: the ARM, section 13.4.6, "Class Member Access" says
"it follows that operator->() must return either a pointer to a class or an
object of or a reference to a class for which operator->() is defined."
So the following is illegal:

    struct s {
 int operator->(); // cfront 2.1 complains about this line.
 };
    void f() {
 s an_s;
 s->m;   // g++ 1.37.1 complains about this line.
 }

I think the g++ behaviour is "more standard", because s. 13.4.6 is about
"->" expressions, not declarations.  In other words, the sentence means "it
follows that the result of a -> expression must be either..."  (There is
also the statement near the top of p. 331: "Note that--except for operator
new() and operator delete()--there are no restrictions on the return types
of overloaded operators."  But that statement is in an annotation, so it
doesn't really count.)

The g++ "illegal when called" approach makes it easier to write template
classes that define operator->().  Consider a template for a Set class that
contains copies of values as opposed to pointers to objects.  Set comes
with a companion Generator class.  Generators act like constant objects of
a set's element type.  They take on each of the values in a set in turn,
and are used as loop indices.

    template<class Elt> class Set;
    template<class Elt> class Generator { ...
      public:
            operator Elt(); // Copy the current value.
 const Elt  operator->(); // Member access through current value.
 void       in(Set<Elt>&); // Begin generating values.
 friend int more(Generator); // Are there more values?
 friend void next(Generator&); // Go get the next value.
 };
    Set<int>       si;
    Generator<int> gi;
    int            sum_sq = 0;
    for (gi.in(si); more(gi); next(gi)) // for every element in si ...
        sum_sq += gi*gi;                // Conversion via operator Elt().

Generator has an operator->() in case Elt is a pointer to a class.

    class Employee { ... };
    Set<Employee*>  se;
    Generator<Employee*> ge;
    for (ge.in(se); more(ge); next(ge)) // for every element in se ...
 cout << ge->name << ge->department;

However, a compile-time error message should be generated if operator->()
is applied to a Generator<int>.  If the rules about result types are
enforced when operator->() is used, then an error will be reported if
_and_only_if_ "->" is applied to a Generator<int>.  If the rules are
enforced when operator->() is declared, then either the template or the
instantiation Generator<int> will produce an error, and this Generator
approach must be abandoned.

    Glen Ditchfield  gjditchfield@violet.uwaterloo.ca  Office: DC 2517
Dept. of Computer Science, U of Waterloo, Waterloo, Ontario, Canada, N2L 3G1
       These opinions have not been tested on animals.