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