Leor Zolman posted this example on comp.lang.c++ http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=due8b09cd2lp3kip4ivtcrn2m3nu6jvmuu%404ax.com It seems according to the standard that the code below is illegal. However it is accepted by all compilers I know of. I verified that 3.4.0 accepts the code below. #include <iostream> using std::cout; using std::endl; class A; class B { public: typedef void (A::*ftype)(); void CallIt(A *ap, ftype f) { (ap->*f)(); // Is this legal with ptr to incomplete type A? } }; class A { public: void method_for_B() { std::cout << "In method_for_B...()" << std::endl; } }; int main() { void (A::*fp)() = &A::method_for_B; A a1; B b1; b1.CallIt(&a1, fp); return 0; }
Not a bug. From the standard, 8.3.3: class Y; char Y::* pmc; ... Similarly, the declaration of pmc is well-formed even though Y is an incomplete type.
(In reply to comment #1) > Not a bug. > From the standard, 8.3.3: > class Y; > char Y::* pmc; > ... > Similarly, the declaration of pmc is well-formed even though Y is an incomplete type. OK, I'm no expert, but all it says is that the declaration is well-formed, not that you can actually use it (the way they show pmi and pmf being used) -leor
Why do you think it will not work, as the point-to-member function type is just have a reference to the offset at which you call the function nothing more (well there is more but that is an ABI definition). Since the pointer-to-member type includes all the needed info there is no reason why it should not work.
> Why do you think it will not work ... I think it's not a question of wether it works or not, it's more an issue of wether it is legal according to the standard. In the c.l.c++ thread I cited earlier, there is an assertion that a call can only be made when the class is complete. I personally like the gcc behaviour and if anything I'd like to see this caught in strict mode only. An alternative would be to write up a defect report on the standard since it seems all the compilers are consistant ! I don't have my copy of the standard handy to I can't say for sure.
I cannot find where in the C++ standard that this is invalid and in the thread it only says that they contracted EDG, if you think this is an issue, raise it to comp.lang.c++.moderated instead and then when they decide it is invalid you can reopen this bug.
Always this already came up in that newsgroup before: <http://groups.google.com/groups? hl=en&lr=&ie=UTF-8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner- bank.com&rnum=1&prev=/groups%3Fq%3Dincomplete%2Btypes%2Bpointer%2Bto%2Bmember%2Bgroup: comp.lang.c%252B%252B.moderated%26hl%3Den%26lr%3D%26ie%3DUTF -8%26group%3Dcomp.lang.c%252B%252B.moderated%26c2coff%3D1%26selm%3D3ACC2828.45CA0D3C %2540dresdner-bank.com%26rnum%3D1>.
(In reply to comment #5) > I cannot find where in the C++ standard that this is invalid and in the thread it only says that they > contracted EDG, if you think this is an issue, raise it to comp.lang.c++.moderated instead and then > when they decide it is invalid you can reopen this bug. The citation from the standard is (5.5p3): 3 The binary operator ->* binds its second operand, which shall be of type "pointer to member of T" (where T is a completely-defined class type) to its first operand, which shall be of type "pointer to T" or "pointer to a class of which T is an unambiguous and accessible base class." The result is an object or a function of the type specified by the second operand. "where T is a completely-defined class type" is pretty cut-and-dried. Plus, as John Spicer has indicated to me in a private email: "An implementation could choose different forms of pointer-to-member representations depending on whether or not the class had virtual functions, or something like that. In such implemenations, a complete type would be needed to get correct behavior." -leor
Read the link I gave gives a different story in that it is always valid.
About Leor's citation on virtual's being difficult. It seems like it's not so hard after all. BTW I also tried this example where B::CallIt was in a different translation unit and it all worked fine. So, while I can agree that you might need different implementation for pointer to virtual member function and regular member functions, it seems like gcc at least has no such issue. (tested on 3.4.0). #include <iostream> using std::cout; using std::endl; class A; class B { public: typedef void (A::*ftype)(); void CallIt(A *ap, ftype f) { (ap->*f)(); // Is this legal with ptr to incomplete type A? } }; class A { public: virtual void method_for_B() { std::cout << "A In method_for_B...()" << std::endl; } }; class AX : public A { public: virtual void method_for_B() { std::cout << "AX In method_for_B...()" << std::endl; } }; int main() { void (A::*fp)() = &A::method_for_B; AX a1; B b1; b1.CallIt(&a1, fp); return 0; } oh - here is the link again, hopefully without wrapping http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner-bank.com&rnum=1&prev=/groups%3Fq%3Dg:thl1416673164d%26dq%3D%26hl%3Den%26lr%3D%26ie%3DUTF-8%26c2coff%3D1%26selm%3D3ACC2828.45CA0D3C%2540dresdner-bank.com
> oh - here is the link again, hopefully without wrapping > http://groups.google.com/groups?hl=en&lr=&ie=UTF- 8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner-bank.com&rnum=1&prev=/groups% 3Fq%3Dg:thl1416673164d%26dq%3D%26hl%3Den%26lr%3D%26ie%3DUTF-8%26c2coff%3D1% 26selm%3D3ACC2828.45CA0D3C%2540dresdner-bank.com That worked. I'm confused by some things Kanze says in that article. First, there's this: The question was whether you can take a pointer to member function on an incomplete class. I don't think that the standard says anything about this directly. But the way I read it, 5.5.3 is /very/ clear and direct. You can't do it. Then there's this: More generally, the standard always specifies when an incomplete type is illegal; using an incomplete type in a context which requires a complete type makes the program ill-formed, and requires a diagnostic. Considering this, it is interesting that 5.5 makes no such restriction. I interpret this to mean that you can also dereference the pointer without completing the type; the following is legal: class X ; void f( X* pc , void (X::*pmf)() ) { (pc->*pmf)() ; } Here again, the Standard says something must be a complete type (OK, the term actually used is "completely-defined", but I'm assuming that's the same thing), and Kanze is saying that the Standard "always specifies" when an incomplete type is illegal? As if saying something "must be completely-defined" is insufficient? Kanze goes on to show the /exact/ situation we're talking about, but he seems to think the Standard sanctions it. Help me out here, I don't get it. -leor
Given the quote from the standard, I think this is pretty clearly a bug
Confirmed, note that is well defined though as ->* is the pointer-to-member of T only T needs to be completely-defined and not the left side. class A {}; class B; class C { typedef void (A::*ftype)(); C(B* a){a->*ftype();} }
Woops my example is invalid too.
*** Bug 18933 has been marked as a duplicate of this bug. ***
Ok, now we produce an error_mark_node which seems wrong if we don't produce an error.
*** Bug 32416 has been marked as a duplicate of this bug. ***
This is Core DR 1340 which was moved as a DR in 2012, making the standard match what all compilers already did. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1340