[comp.lang.c++] More about Function Pointers

hagerman@pug.ece.cmu.edu (John Hagerman) (08/19/89)

I'd like to thank Scott Danforth for his discussion of typing with
respect to my questions about function pointers.

However, I'm still having some trouble with "what is legal C++" in a
practical sense.  I get the impression that some issues in C++ have
not yet been finally decided upon.  If this is the case for this
situation, I need to know it explicitly, lest I take advantage of a
"feature" that disappears in the future.

My question pivots around a statement in Stroustrup:

Section 4.6.9:

	In pointer assignments, the complete function type must
	match exactly.

(I can't find this statement in any Reference Manual section.)

This seems reasonable to me.  If the match was not exact, then type
conversions would be necessary.  But the proper conversions cannot be
known at compile time.  Consider how argument conversion is done:

Section 4.6.3:

	The semantics of argument passing are identical to the
	semantics of initialization.  In particular, the type of an
	actual argument is checked against the type of the
	corresponding formal argument and all standard and
	user-defined type conversions are performed.

(Sec. r7.1 elaborates on the meaning of "function call," and no
distinction is made between calls via name versus pointer.)

For a call via pointer, I presume that the formal argument types are
determined from the type of the pointer, since the types of the formal
arguments of the pointed-to function cannot be known at compile time.
Therefore, no conversions can be made to accomodate the types of the
formal arguments of the pointed-to function.  Thus, the exact match
specified in Section 4.6.9 is required.

I would think that this restriction would include implicit inheritance
conversions (Sections r6.7, r6.8, and r8.6.3).  That is, *neither* of
the assignments of my previous post should be valid.  For multiple
inheritance, such conversions might be more than the null conversion,
mightn't they?

Here's a simplified example:

-----

class B { };

class D : public B { };

void f_b(B&);			// func taking base class arg
void f_d(D&);			// func taking derived class arg

void (*pf_b_1)(B&) = f_b;	// ok
void (*pf_d_1)(D&) = f_d;	// ok

void (*pf_b_2)(B&) = f_d;	// bad, tiemann implies it's a
				//      feature that g++ accepts it
void (*pf_d_2)(D&) = f_b;	// bad, tiemann says it's a bug
				//      that g++ doesn't accept it

-----

So the questions are these: Does the statement in Section 4.6.9 really
mean "exact match?"  Do I understand the semantics of function call?

I don't know if this is the place to note this, but there are some
minor typos in Sections r6.7 and r6.8.

Thanks in advance for any explanations - John
hagerman@ece.cmu.edu