Topic: Q: conversion of meth. pointers
Author: kiemes@us-es.sel.de (Martin Kiemes US/ESB2 60/3/156 #42478)
Date: 31 Jan 95 09:58:20 GMT Raw View
Hi,
I forwarded the article to a colleague of mine who has no news.
He responded as follows:
|> In article <3giki1$8q9@news.uni-paderborn.de>, cadi@pollux.uni-paderborn.de (Carsten Ditze) writes:
|> > The following lines will show a small program, that compiles fine with the
|> > CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
|> >
|> > #include <stream.h>
|> >
|> > class Base;
|> > typedef void (Base::*PMFV)();
|> >
|> > class Base {
|> > public:
|> > void callMethod(PMFV meth) {
|> > (this->*meth)();
|> > }
|> > };
|> >
|> >
|> > class Foo : public Base {
|> > public:
|> > void helloFoo() { cout << "This is Foo\n"; }
|> > };
|> >
|> >
|> > int main()
|> > {
|> > Base b;
|> > Foo f;
|> >
|> > // won't compile with g++: "conversion to non-scalar type requested"
|> > f.callMethod((PMFV)&Foo::helloFoo);
|> > }
|> >
|> > Since I want to write compiler independent code, I'd appreciate a comment of
|> > the standardization group (and of the GNU group concering future versions).
|> >
|> > Thus: Will pointer to methods conversion be allowed in the standard, so that
|> > those pointer can be passed as an parameter to *any* other method/function?
|> > I'd vote for "yes" because conversion of pointers to functions does not show
|> > these restrictions!
This point has only recently been clarified in the standards
committee.
The above code will be legal, and will do what is expected.
G++ 2.6.3 compiles it OK (but since g++ 2.6.3 won't compile libg++, at
least not under Solaris 2, I can't test to see whether it actually
runs:-(.)
I might add that some other compilers which did compile it before did
not interpret the semantics in the way the standards committee decided
(and that one would expect). Since in this case, it will compile, but
in the presence of multiple inheritance, will core dump on running, I
would avoid the construct in portable code.
BTW: as I haven't had time to install news on my local machine, if
there are no other responses, feel free to post this.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
--Beratung in industrieller Datenverarbeitung
--
Martin Kiemes Email: kiemes@lts.sel.alcatel.de Alcatel SEL AG
Dept. US/ESB Phone: +49-711-821-2478 Lorenzstrasse 10
Room 60/3/156 Fax: +49-711-821-7045 D-70435 Stuttgart
Author: pstemari@erinet.com (Paul J. Ste. Marie)
Date: Tue, 31 Jan 1995 22:51:17 EST Raw View
In article <1995Jan31.095820.4841@lts.sel.alcatel.de> kiemes@us-es.sel.de (Martin Kiemes US/ESB2 60/3/156 #42478) writes:
> ... (upcasted member function pointer example deleted) ...
>I might add that some other compilers which did compile it before did
>not interpret the semantics in the way the standards committee decided
>(and that one would expect). Since in this case, it will compile, but
>in the presence of multiple inheritance, will core dump on running, I
>would avoid the construct in portable code.
I don't particularly see why a core dump is unavoidable. If a base class MFP
is casted down implicitly to a derived class MFP, the compiler must create an
offset for the this pointer, either as a component of the MFP or via a thunk.
If you go the opposite direction with an explicit cast, then the negative of
that offset should be created, avoiding the core dump.
Example--given class C : public A, public B and a B MFP, you can assign the B
MFP to a C MFP and a this pointer offset equal to sizeof(A) is created. Why
can't you simply use a this pointer offset equal to -sizeof(A) when a C MFP is
explicitly casted to a B MFP?
The formula for the this pointer offset would be as follows:
offset = oldoffset + (char *) (casttotype *) (castfromtype *) 1
- (char *) (castfromtype *) 1;
A similar formula exists for vtable indexes, as long as the vtable for the
derived class contains entries for all virtual functions, and not just those
declared in the class:
index = oldindex - (casttovptr - castfromvptr);
Paul J. Ste. Marie,
pstemari@well.sf.ca.us, pstemari@erinet.com
Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 31 Jan 1995 23:43:47 GMT Raw View
>>>>> Carsten Ditze <cadi@pollux.uni-paderborn.de> writes:
> The following lines will show a small program, that compiles fine with the
> CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
>...
> // won't compile with g++: "conversion to non-scalar type requested"
> f.callMethod((PMFV)&Foo::helloFoo);
>...
> Since I want to write compiler independent code, I'd appreciate a comment
> of the standardization group (and of the GNU group concering future
> versions).
Future versions? That bug is fixed in current versions (2.6.[1-3]).
> Thus: Will pointer to methods conversion be allowed in the standard, so that
> those pointer can be passed as an parameter to *any* other
> method/function? I'd vote for "yes" because conversion of pointers to
> functions does not show these restrictions!
That conversion has undefined semantics:
5.2.8 Static cast [expr.static.cast]
8 An rvalue of type pointer to member of D of type cv T where D is a
class type, may be converted to an rvalue of type pointer to member of
B of type cv T, where B is a base class (_class.derived_) of D, if a
valid pointer conversion from pointer to cv D to pointer to cv B
exists (_conv.ptr_). The null member pointer value (_conv.mem_) is
converted to the null member pointer value of the destination type.
If the pointer to member converted is not the null member pointer
value and class B does not contain or inherit the original member, the
result of the cast is undefined.
Jason
Author: bgibbons@taligent.com (Bill Gibbons)
Date: Thu, 2 Feb 1995 18:49:08 GMT Raw View
In article <JASON.95Jan31154347@phydeaux.cygnus.com>, jason@cygnus.com
(Jason Merrill) wrote:
> That conversion has undefined semantics:
>
> 5.2.8 Static cast [expr.static.cast]
>
> 8 An rvalue of type pointer to member of D of type cv T where D is a
> class type, may be converted to an rvalue of type pointer to member of
> B of type cv T, where B is a base class (_class.derived_) of D, if a
> valid pointer conversion from pointer to cv D to pointer to cv B
> exists (_conv.ptr_). The null member pointer value (_conv.mem_) is
> converted to the null member pointer value of the destination type.
> If the pointer to member converted is not the null member pointer
> value and class B does not contain or inherit the original member, the
> result of the cast is undefined.
>
> Jason
This issue is still under discussion. The above wording reflects the
minimum functionality which the committee has agreed upon; additional
functionality - in particular, casting to a base class which does not
contain or inherit the original member - has yet to be decided.
(By default, of course, there will be no additional functionality.)
I have formally proposed to the committee that the restriction should
be relaxed so that a pointer to member may also be cast to a nonvirtual
base class of the class containing the original member.
Of course, when the pointer to member is dereferenced, the object must
actually contain the member to which the pointer refers.
--
Bill Gibbons
bgibbons@taligent.com
Author: jbuck@synopsys.com (Joe Buck)
Date: 2 Feb 1995 19:25:45 GMT Raw View
cadi@pollux.uni-paderborn.de (Carsten Ditze) writes:
>The following lines will show a small program, that compiles fine with the
>CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
2.5.8 had a problem with casts converting one type of pointer to
member function to another. The bug was fixed in version 2.6.0.
The current g++ version is 2.6.3.
--
-- Joe Buck <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729
Author: cadi@pollux.uni-paderborn.de (Carsten Ditze)
Date: 30 Jan 1995 12:03:13 GMT Raw View
The following lines will show a small program, that compiles fine with the
CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
#include <stream.h>
class Base;
typedef void (Base::*PMFV)();
class Base {
public:
void callMethod(PMFV meth) {
(this->*meth)();
}
};
class Foo : public Base {
public:
void helloFoo() { cout << "This is Foo\n"; }
};
int main()
{
Base b;
Foo f;
// won't compile with g++: "conversion to non-scalar type requested"
f.callMethod((PMFV)&Foo::helloFoo);
}
Since I want to write compiler independent code, I'd appreciate a comment of
the standardization group (and of the GNU group concering future versions).
Thus: Will pointer to methods conversion be allowed in the standard, so that
those pointer can be passed as an parameter to *any* other method/function?
I'd vote for "yes" because conversion of pointers to functions does not show
these restrictions!
Thanx a lot for your help,
Carsten
--
+------------------------------------------------------------------------+
| Carsten Ditze | e-mail: cadi@uni-paderborn.de |
| University of Paderborn | or: cadi@pbinfo.uucp |
| FB 17 (Dept. of Math. & CS) | or: ...!uunet!unido!pbinfo!cadi |
| | voice: +49 +5251 60-2074 |
| 33095 Paderborn, Germany | fax: +49 +5251 60-3427 |
+------------------------------------------------------------------------+
Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 30 Jan 95 19:41:05 GMT Raw View
cadi@pollux.uni-paderborn.de (Carsten Ditze) writes:
>The following lines will show a small program, that compiles fine with the
>CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
>#include <stream.h>
>class Base;
>typedef void (Base::*PMFV)();
>class Base {
> public:
> void callMethod(PMFV meth) {
> (this->*meth)();
> }
>};
>class Foo : public Base {
> public:
> void helloFoo() { cout << "This is Foo\n"; }
>};
>int main()
>{
> Base b;
> Foo f;
> // won't compile with g++: "conversion to non-scalar type requested"
> f.callMethod((PMFV)&Foo::helloFoo);
>}
>Since I want to write compiler independent code, I'd appreciate a comment of
>the standardization group (and of the GNU group concering future versions).
>Thus: Will pointer to methods conversion be allowed in the standard, so that
> those pointer can be passed as an parameter to *any* other method/function?
> I'd vote for "yes" because conversion of pointers to functions does not show
> these restrictions!
Your code is incorrect; hellofoo is NOT a member of Base, so the
conversion is not allowed. The conversion in the opposite direction
(pointer to member (or member function) of base to pointer to member
of a derived class) is specifically allowed by the ARM, but some
compilers refuse to do it when virtual bases are involved. It
clearly is possible to handle this case, as the Borland compiler
supports all such cases.
Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 30 Jan 1995 13:41:05 -0600 Raw View
cadi@pollux.uni-paderborn.de (Carsten Ditze) writes:
>The following lines will show a small program, that compiles fine with the
>CC version 4.0 of the SunOS, but it fails using the g++ 2.5.8:
>#include <stream.h>
>class Base;
>typedef void (Base::*PMFV)();
>class Base {
> public:
> void callMethod(PMFV meth) {
> (this->*meth)();
> }
>};
>class Foo : public Base {
> public:
> void helloFoo() { cout << "This is Foo\n"; }
>};
>int main()
>{
> Base b;
> Foo f;
> // won't compile with g++: "conversion to non-scalar type requested"
> f.callMethod((PMFV)&Foo::helloFoo);
>}
>Since I want to write compiler independent code, I'd appreciate a comment of
>the standardization group (and of the GNU group concering future versions).
>Thus: Will pointer to methods conversion be allowed in the standard, so that
> those pointer can be passed as an parameter to *any* other method/function?
> I'd vote for "yes" because conversion of pointers to functions does not show
> these restrictions!
Your code is incorrect; hellofoo is NOT a member of Base, so the
conversion is not allowed. The conversion in the opposite direction
(pointer to member (or member function) of base to pointer to member
of a derived class) is specifically allowed by the ARM, but some
compilers refuse to do it when virtual bases are involved. It
clearly is possible to handle this case, as the Borland compiler
supports all such cases.