[comp.std.c++] Return type of operator->

gjditchfield@watmsg.uwaterloo.ca (Glen Ditchfield) (04/02/91)

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.