[comp.lang.c++] A question of references

jeffb@grace.cs.washington.edu (Jeff Bowden) (05/08/89)

Here's the deal.  I've got a function in C which I am translating to C++.
Here is an abstraction of what the current function does:

	T *foo[ROWS][COLS];

	/* ... */

	void bar(/* args... */)
	{
	  T **d = &foo[r][c];

	  /* Many uses of `d' all of the form ``(*d)'' */
        }

Obviously, `d' is crying out ``I'm really a reference!''.  Now, since c++ has
this nifty ability to specify references I would like to declare `d' as such
and change all instances of ``(*d)'' to ``d''.

Problem is, I can't figure out how to declare it.  Obviously (?) it should be
either
	T *&d = ...
or
	T &*d = ....

But which?  And how, in general, do you figure it out?  I think the relevant
part of Stroustrup starts on page 269.  To wit:

      ``Now imagine a declaration

		T D1

	where `T' is a type-specifier (like `int', etc.) and `D1' is a
	declarator.

	...

	If D1 has the form

		&D
	or

		& const D

	the type of the contained identifier is `... reference to T.' ''
				  ^^^^^^^^^^

This leads me to think that either order doesn't matter or that in all cases
the "&" has to be the first thing.  The former seems unlikely so my guess is
that

	T &*d = ...

is what I want.  Is my interpretation correct or is there some other place in
Stroustrup which is more explicit about how references should really be
declared.


I realize that I could just test the possibilities out with a compiler but it
seems as though this really ought to be clearly documented and I'd like to
know where.
--
Say "lah vee."

hansen@pegasus.ATT.COM (Tony L. Hansen) (05/08/89)

< Summary: How do you declare a reference to a pointer to T?

$ c++decl
c++decl> declare x as reference to pointer to class y
class y *&x

That's how I do it.

					Tony Hansen
				att!pegasus!hansen, attmail!tony
				    hansen@pegasus.att.com

pcg@aber-cs.UUCP (Piercarlo Grandi) (05/08/89)

In article <JEFFB.89May7132808@grace.cs.washington.edu>
jeffb@grace.cs.washington.edu (Jeff Bowden) writes:
    
    Here's the deal.  I've got a function in C which I am translating to C++.
    Here is an abstraction of what the current function does:
    
    	T *foo[ROWS][COLS];
    
    	/* ... */
    
    	void bar(/* args... */)
    	{
    	  T **d = &foo[r][c];

    	  /* Many uses of `d' all of the form ``(*d)'' */
        }
    
    Obviously, `d' is crying out ``I'm really a reference!''.

Not so obviously. A reference is a synonym for an lvalue, i.e. a way to
redefine an identifier (I hope that nobody takes seriously BS on the bottom
of page 56 about `double &dr = 1;' :->). There are two cases:

	[1] you want `d' to always denote the `T' pointer at `foo[r][c]'
	[2] you want to step `d' thru `foo', starting at `foo[r][c]'

In the first case then `d' is a reference of type `T *', so that `&d ==
&foo[r][c]'; in the second it is a pointer indeed.

    Now, since c++ has this nifty ability to specify references I would like
    to declare `d' as such and change all instances of ``(*d)'' to ``d''.

So assuming that `d' is not used as a pointer, but as a synonym:

	auto T *(&d) = (foo[r][c]);

where the paranthesis are used to emphasize the fact that `(&d)' is a reference
of type `T *', just like `(foo[r][c])'; if you prefer you can also write

	typedef T *Tp;
	auto Tp &d = foo[r][c];

[Note the auto: in C++ it helps a lot (the compiler and yourself) to ALWAYS
start a declaration with a storage class, especially if the declaration
begins with a typedef'd type.  I would like this to be made a rule, it would
make compiler writing and program reading that much easier. Compare

	yards * length

with

	auto yards *length

or similar ambiguities. Too bad about breaking a lot of C programs, but then
the rule that `struct s v;' and `s v;' are now equivalent already breaks all
the C programs -- many -- in which one writes `struct screen screen' or
similar verbiage...]

While I agree that:
    
    I think the relevant part of Stroustrup starts on page 269.  To wit:
    
          ``Now imagine a declaration
    
    		T D1
    
    	where `T' is a type-specifier (like `int', etc.) and `D1' is a
    	declarator.
    
    	...
	^^^

the omitted part is essential, because it gives the rules for the `*'
declaration operator, and they turn out to be identical to those of `&'.
Your isolated quotation:
    
    	If D1 has the form
    
    		&D
    	or
    
    		& const D
    
    	the type of the contained identifier is `... reference to T.' ''
    				  ^^^^^^^^^^

makes `&' appear different from `*', which (I hope) is not what is meant.
Note that `D' is a declarator, and can specify (recursively) more complex
syntax. Does this mean that 

	auto int &j = i; auto int &(&k) = j;

	auto int &(*ip) = ???; /* (*ip) is a reference ? */

are legal indeed?  Certainly

	extern char &(last(char []));

is legal, but then what about:

	extern void (&oops)();

On page 271, 3rd paragraph, BS says

	Not all the possibilities allowed by the above syntax are permitted.
	The restrictions are: [ ... about arrays and functions ... ]

Should this list be extended? References may deserve extending the list
of restrictions...

Note the length of the discussion for a simple point: C++ is the language
laywer's paradise (as if PL/1 and Ansi C were not enough... :-] :-]).
-- 
Piercarlo "Peter" Grandi           | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcvax!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk