Topic: Does 'typedef void (B::*PMB)();' require B to be def'd or just decl'd?


Author: swf@ElSegundoCA.NCR.COM (Stan Friesen)
Date: Thu, 18 Aug 94 09:53:41 PDT
Raw View
In article <KANZE.94Aug17180608@slsvhdt.us-es.sel.de>, kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 #71425) writes:
|> In article <9408161540.AA09166@tdat.ElSegundoCA.NCR.COM>
|> swf@ElSegundoCA.NCR.COM (Stan Friesen) writes:
|>
|> |> In article <CuHxtt.LxG@microsoft.com>, jangr@microsoft.com (Jan Gray) writes:
|>
|> |> |> Since if all you know about the PM "basis class" (as I call them)
|> |> |> is that it *is* a forward declared class, you must represent the PM in
|> |> |> its most general possible implementation.  That is, given
|> |> |>   struct X; int (X::*pmfX)();
|> |> |> our object model can store it in
|> |> |>   1 word  if X known to have used no or just single inheritance
|> |> |>   2 words if X known to have used multiple inheritance
|> |> |>   3 words if X known to have used virtual inheritance
|> |> |>   4 words if we don't yet know and have to represent any of the above
|>
|> |> Gads!  Doesn't anybody remember two-pass compilers anymore!
|> |> Consider alternative 5:
|> |>  enter it in the symbol table in pass 1, and decide the size in pass 2.
|>
|> Doesn't help.  You still don't know who may derive from the class in
|> other modules, nor how.

This is irrelevent, as the compiler can *never* know that, as modules
are independent in C++, as in C.  What is under consideration is whether
class/struct *X* is singly, multiply, or virtually derived from its base
class(es).

What we are discussing is the MS C++ restriction that to declare a typedef
for a pointer-to-member, the full declaration of the class portion must be
in scope at the point of the typedef.  What classes are *derived* from
X are not relevent, as they are not part of the full declaration of X.

So, yes, a two-pass approach helps, since to be useful the full declaration
of the class must be made visible at some point, thus allowing the forward
declaration of X to be filled in on the second pass.
|>
|> |> Or simply require the "basis" class to be defined when an actual *object*
|> |> of the PM type is declared, as another poster suggested, if you find the
|> |> idea of a two-pass compiler too horrifying to contemplate.
|>
|> Again, when a PM type is declared, the compiler has know way of
|> knowing what is happening with the class in other modules, nor whether
|> the address of a virtual function will be assigned to it.

See above.

--
swf@elsegundoca.ncr.com  sarima@netcom.com

The peace of God be with you.




Author: jangr@microsoft.com (Jan Gray)
Date: Sat, 13 Aug 1994 23:13:02 GMT
Raw View
In article <rfgCu8Bwq.K21@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>Anyway, in this case, other folks had already pointed out that vendor M's
>implementation (where `M' shall remain nameless :-) requires one to either
>set some GUI toggle or else to include a #pragma just to get (draft)
>standard conformant behavior.  That doesn't sound either reasonable or
>user-friendly to me, but then I guess vendor `M' has its own customer
>base, and its own reasons for making NON-standard conformant behavior
>the default. :-(

The switch and #pragma overridable default for MS Visual C++ is to require
a class X to be defined before we permit it to be the basis class for a
pointer to member type declaration.  That is, by default we flag this:
  struct X; int (X::*pmfX)(); // an error
but permit this:
  struct Y { ... }; int (Y::*pmfY)(); // OK

This is the default for two very good reasons.  1. we take generated
code quality very seriously, and 2. we were determined to implement
full pointers-to-members semantics, for all manner of inheritance,
not just a single- or mulitple-inheritance subset.

The realities of implementing pointers-to-members (PMs) are that no
inheritance, single inheritance (SI), and multiple inheritance (MI)
PMs are simpler to store (1 or 2 machine words) and to cast and
dereference than are virtual inheritance (VI) PMs (3-4 words).
Since if all you know about the PM "basis class" (as I call them)
is that it *is* a forward declared class, you must represent the PM in
its most general possible implementation.  That is, given
  struct X; int (X::*pmfX)();
our object model can store it in
  1 word  if X known to have used no or just single inheritance
  2 words if X known to have used multiple inheritance
  3 words if X known to have used virtual inheritance
  4 words if we don't yet know and have to represent any of the above

When you consider that, and consider that the vast vast majority of
our users are not using pointers to members with classes with
virtual inheritance, to "inflict" multiword PMs (with far inferior
generated code sequences for actual use) on all our users was not
judged acceptable.  Instead, for a minor inconvenience in those
(also rare) code bases which use pointers to members to classes
which are as yet only forward declared in the current translation
unit, we ensure *optimal* PM representations and operations
in all other cases.

We also knew that some code bases could not be modified to ensure
the basis class was defined before declaring PMs to it, and so
added a variety of convenience mechanisms, including compile flags,
#pragmas, and even an extension to declare a forward declared
class will ultimately use a certain kind of inheritance
(e.g. "class __single_inheritance X;") to make it easy to cope
in case you really want to have fat slow representations of
your PMs.

Also note these decisions were made at a time when cfront's
support for VI PMs was of the "sorry not implemented" variety.
Since cfront didn't implement virtual inheritance PMs,
not to mention pointers to members of several layers deep
transitively virtually inherited classes, it was no problem
for it to use a single representation of all PMs and
thus to not require the "basis class" (and therefore the
PM representation choice) to be defined.
Before you cast aspersions, compare the size and generated
code for your fave compiler's PMs for simple classes and
for fancy virtually inherited classes like G:
  struct A { int a(); }; struct B : virtual A { int b(); };
  struct C : virtual A { int c(); }; struct D : B, C { int d(); };
  struct E : virtual D { int e(); }; struct F : virtual D { int f(); };
  struct G : E, F { int g(); };

Also, I haven't reviewed this in the latest working papers,
but at the time it was certainly the case that there was no
requirement for, or against, this kind of restriction; further
even today I do not think the semantics of PMs are well defined
for PM *operations* like casts when "basis classes" are only
forward declared.  Are you so certain the working papers provide
that a program which creates and operates upon PMs of undefined
classes is well defined?

Regards.
Jan Gray // Microsoft Visual C++ Development




Author: jjb@watson.ibm.com (John Barton)
Date: Mon, 15 Aug 1994 12:59:13 GMT
Raw View
In article <CuHxtt.LxG@microsoft.com>, jangr@microsoft.com (Jan Gray) writes:
|> In article <rfgCu8Bwq.K21@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
|> >Anyway, in this case, other folks had already pointed out that vendor M's
|> >implementation (where `M' shall remain nameless :-) requires one to either
|> >set some GUI toggle or else to include a #pragma just to get (draft)
|> >standard conformant behavior.  That doesn't sound either reasonable or
|> >user-friendly to me, but then I guess vendor `M' has its own customer
|> >base, and its own reasons for making NON-standard conformant behavior
|> >the default. :-(
|>
|> The switch and #pragma overridable default for MS Visual C++ is to require
|> a class X to be defined before we permit it to be the basis class for a
|> pointer to member type declaration.  That is, by default we flag this:
|>   struct X; int (X::*pmfX)(); // an error
|> but permit this:
|>   struct Y { ... }; int (Y::*pmfY)(); // OK
|>
|> This is the default for two very good reasons.  1. we take generated
|> code quality very seriously, and 2. we were determined to implement
|> full pointers-to-members semantics, for all manner of inheritance,
|> not just a single- or mulitple-inheritance subset.
|>
[...interesting detailed analysis deleted...]

   Even if no other compiler takes generated code quality seriously, :-)
the ANSI committee exists to insure that full pointers-to-members
semantics are defined and adhered-to by conformant compilers.  I think
it pretty clear that that subject line example differs from the
one posted here. I hope that the standard will work like this:

  struct X;
  typedef int (X::*pmfX)();  // Legal, no warnings, no waffles.
  int (X::*a_pmfX)();        // Programmer Error.

As Jan Gray's post details, the latter case is a definition of
a variable "a_pmfX" whose type must be defined at point of
definition.  Its type definition includes the class DAG info
in the type X.  Thus the variable definition must follow the
definition of the type X: forward declaration is not enough.
The typedef is different since it is only a reference to a type.

--
John.

John J. Barton        jjb@watson.ibm.com            (914)784-6645
H1-C13 IBM Watson Research Center P.O. Box 704 Hawthorne NY 10598




Author: swf@ElSegundoCA.NCR.COM (Stan Friesen)
Date: Tue, 16 Aug 94 08:40:56 PDT
Raw View
In article <CuHxtt.LxG@microsoft.com>, jangr@microsoft.com (Jan Gray) writes:
|>
|> The realities of implementing pointers-to-members (PMs) are that no
|> inheritance, single inheritance (SI), and multiple inheritance (MI)
|> PMs are simpler to store (1 or 2 machine words) and to cast and
|> dereference than are virtual inheritance (VI) PMs (3-4 words).
|> Since if all you know about the PM "basis class" (as I call them)
|> is that it *is* a forward declared class, you must represent the PM in
|> its most general possible implementation.  That is, given
|>   struct X; int (X::*pmfX)();
|> our object model can store it in
|>   1 word  if X known to have used no or just single inheritance
|>   2 words if X known to have used multiple inheritance
|>   3 words if X known to have used virtual inheritance
|>   4 words if we don't yet know and have to represent any of the above

Gads!  Doesn't anybody remember two-pass compilers anymore!
Consider alternative 5:
 enter it in the symbol table in pass 1, and decide the size in pass 2.

Or simply require the "basis" class to be defined when an actual *object*
of the PM type is declared, as another poster suggested, if you find the
idea of a two-pass compiler too horrifying to contemplate.

--
swf@elsegundoca.ncr.com  sarima@netcom.com

The peace of God be with you.




Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 #71425)
Date: 17 Aug 1994 16:06:08 GMT
Raw View
In article <9408161540.AA09166@tdat.ElSegundoCA.NCR.COM>
swf@ElSegundoCA.NCR.COM (Stan Friesen) writes:

|> In article <CuHxtt.LxG@microsoft.com>, jangr@microsoft.com (Jan Gray) writes:

|> |> The realities of implementing pointers-to-members (PMs) are that no
|> |> inheritance, single inheritance (SI), and multiple inheritance (MI)
|> |> PMs are simpler to store (1 or 2 machine words) and to cast and
|> |> dereference than are virtual inheritance (VI) PMs (3-4 words).
|> |> Since if all you know about the PM "basis class" (as I call them)
|> |> is that it *is* a forward declared class, you must represent the PM in
|> |> its most general possible implementation.  That is, given
|> |>   struct X; int (X::*pmfX)();
|> |> our object model can store it in
|> |>   1 word  if X known to have used no or just single inheritance
|> |>   2 words if X known to have used multiple inheritance
|> |>   3 words if X known to have used virtual inheritance
|> |>   4 words if we don't yet know and have to represent any of the above

|> Gads!  Doesn't anybody remember two-pass compilers anymore!
|> Consider alternative 5:
|>  enter it in the symbol table in pass 1, and decide the size in pass 2.

Doesn't help.  You still don't know who may derive from the class in
other modules, nor how.

|> Or simply require the "basis" class to be defined when an actual *object*
|> of the PM type is declared, as another poster suggested, if you find the
|> idea of a two-pass compiler too horrifying to contemplate.

Again, when a PM type is declared, the compiler has know way of
knowing what is happening with the class in other modules, nor whether
the address of a virtual function will be assigned to it.
--
James Kanze                                  email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue des Francs Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung




Author: shap@cobra.cis.upenn.edu (Jonathan Shapiro)
Date: 9 Aug 1994 16:48:42 GMT
Raw View
In article <rfgCu8Bwq.K21@netcom.com>, rfg@netcom.com (Ronald F.
Guilmette) writes:
> Anyway, in this case, other folks had already pointed out that vendor
> M's
> implementation (where `M' shall remain nameless :-) requires one to
> either
> set some GUI toggle or else to include a #pragma just to get (draft)
> standard conformant behavior.  That doesn't sound either reasonable or
> user-friendly to me...

Ron:

In general, I agree with you that standards conformance should be a
high priority, but customer needs are an even higher priority.

If you're selling a compiler to a Windows developer, they will be doing
their development to Windows first, and then porting to other
environments iff it looks like a win economically to do so.  MS can get
away with being behind the standard.


Jonathan




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 7 Aug 1994 08:40:14 GMT
Raw View
In article <31b8v9INNjt7@life.ai.mit.edu> gillett@raisin-nut.ai.mit.edu (Walter E. Gillett) asks about the validity of:

>class B;
>typedef void (B::*PMB)();

This is interesting for two reasons.

First, it is interesting because of the reports that at least one compiler
will accept this ONLY if it is accompanied by some extra-lingual (and
special) options stashed in a file somewhere.

I suppose that it might be valid for a vendor to insist that we type in
Lincolin's Gettysburg Address and place it in a file called MUSIC.RAP
before we can elicit standard conformant behavior from that particular
vendor's compiler, but any such requirement would seem to me to be rather
extrodinarily unfriendly (on the part of that vendor, and the vendor's
compiler).

Second, the example is interesting because, upon careful reading of the
latest draft C++ standard, it appears that declarations such as:

 typedef void (B::*PMB)();

or even:

 void (B::*pmb)();

are perfectly valid, EVEN IN THE ABSENCE OF ANY PRIOR DECLARATION OF THE
CLASS TYPE `B'!

Given that, I look forward to obtaining implementation(s) which support
such usage. :-)

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: jason@cygnus.com (Jason Merrill)
Date: Sun, 7 Aug 1994 10:34:54 GMT
Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:

> Second, the example is interesting because, upon careful reading of the
> latest draft C++ standard, it appears that declarations such as:

>  typedef void (B::*PMB)();

> or even:

>  void (B::*pmb)();

> are perfectly valid, EVEN IN THE ABSENCE OF ANY PRIOR DECLARATION OF THE
> CLASS TYPE `B'!

Bzzt.  In the absense of any prior declaration of B, those code fragments
are syntactically invalid; the grammar requires that 'B' be a
'class-or-namespace-name'.

Jason




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 7 Aug 1994 21:25:10 GMT
Raw View
In article <JASON.94Aug7033454@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
>
>> Second, the example is interesting because, upon careful reading of the
>> latest draft C++ standard, it appears that declarations such as:
>
>>  typedef void (B::*PMB)();
>
>> or even:
>
>>  void (B::*pmb)();
>
>> are perfectly valid, EVEN IN THE ABSENCE OF ANY PRIOR DECLARATION OF THE
>> CLASS TYPE `B'!
>
>Bzzt.  In the absense of any prior declaration of B, those code fragments
>are syntactically invalid; the grammar requires that 'B' be a
>'class-or-namespace-name'.

OK.  So how about this:

 void (B::pmb)();
 class B { /* ... */ };

There.  Now surely you are not going to tell me that `B' is not the name
of a class in this translation unit!

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: jhalpin@netcom.com (Joe Halpin)
Date: Mon, 8 Aug 1994 00:26:39 GMT
Raw View
In article <rfgCu6oty.Kn@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <JASON.94Aug7033454@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
>>
>>> Second, the example is interesting because, upon careful reading of the
>>> latest draft C++ standard, it appears that declarations such as:
>>
>>>  typedef void (B::*PMB)();
>>
>>> or even:
>>
>>>  void (B::*pmb)();
>>
>>> are perfectly valid, EVEN IN THE ABSENCE OF ANY PRIOR DECLARATION OF THE
>>> CLASS TYPE `B'!
>>
>>Bzzt.  In the absense of any prior declaration of B, those code fragments
>>are syntactically invalid; the grammar requires that 'B' be a
>>'class-or-namespace-name'.
>
>OK.  So how about this:
>
> void (B::pmb)();
> class B { /* ... */ };
>
>There.  Now surely you are not going to tell me that `B' is not the name
>of a class in this translation unit!
>

I don't think the question is whether it's in the translation unit or not,
but whether the compiler has any idea of what the offset of pmb is at the
time of the declaration. I'm not a compiler writer, but from my (basically
intuitive) point of view, it seems to me that the compiler would need to
know what B is before it sets up symbols for components of B. I assume
that's the same reason you can't use incompletely defined structs as part
of another definition.
--
Joe Halpin
jhalpin@netcom.com
---------------------------------------------------------------------------




Author: jason@cygnus.com (Jason Merrill)
Date: Sun, 7 Aug 1994 23:00:43 GMT
Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:

>> Bzzt.  In the absense of any prior declaration of B, those code fragments
>> are syntactically invalid; the grammar requires that 'B' be a
>> 'class-or-namespace-name'.

> OK.  So how about this:

>  void (B::pmb)();
>  class B { /* ... */ };

> There.  Now surely you are not going to tell me that `B' is not the name
> of a class in this translation unit!

Nope.  I am going to tell you that `B' is not a class-name at that point.
class-name is a syntactic category based on name lookup.  Since B has not
been previously declared, no class is found, so `B' is lexed as a plain
identifier.

I suspect that all the MS-Windows groups don't care about this particular
bit of pedanticism, so I've removed them from the newsgroups line.

Jason




Author: jjb@watson.ibm.com (John Barton)
Date: Mon, 8 Aug 1994 12:09:16 GMT
Raw View
In article <rfgCu5pF3.6yA@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
|> In article <31b8v9INNjt7@life.ai.mit.edu> gillett@raisin-nut.ai.mit.edu (Walter E. Gillett) asks about the validity of:
|>
|> >class B;
|> >typedef void (B::*PMB)();
|>
|> This is interesting for two reasons.
|>
|> First, it is interesting because of the reports that at least one compiler
|> will accept this ONLY if it is accompanied by some extra-lingual (and
|> special) options stashed in a file somewhere.
|>

Ron, as our favorite iconoclast raging against fuzzy thinking, perhaps
you can finger the compiler rather than passing along rumors?  Its not
IBM's C Set ++ v2.1, the above program compiles with a warning:
  "B" is undefined.  Every variable of type "void(B::*)()" will assume
  "B" has no virtual bases and does not use multiple inheritance.
I ran across this a few months ago and I think I convinced our
compiler people to remove the warning and try to place it where the
typedef is used.

--
John.

John J. Barton        jjb@watson.ibm.com            (914)784-6645
H1-C13 IBM Watson Research Center P.O. Box 704 Hawthorne NY 10598




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 8 Aug 1994 18:41:14 GMT
Raw View
In article <Cu7trG.9A9@hawnews.watson.ibm.com> jjb@watson.ibm.com (John Barton) writes:
>In article <rfgCu5pF3.6yA@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>|> In article <31b8v9INNjt7@life.ai.mit.edu> gillett@raisin-nut.ai.mit.edu (Walter E. Gillett) asks about the validity of:
>|>
>|> >class B;
>|> >typedef void (B::*PMB)();
>|>
>|> This is interesting for two reasons.
>|>
>|> First, it is interesting because of the reports that at least one compiler
>|> will accept this ONLY if it is accompanied by some extra-lingual (and
>|> special) options stashed in a file somewhere.
>|>
>
>Ron, as our favorite iconoclast raging against fuzzy thinking, perhaps
>you can finger the compiler rather than passing along rumors?  Its not
>IBM's C Set ++ v2.1...

Sorry.  I try not to pick on customers (or potential customers) by name.

Anyway, in this case, other folks had already pointed out that vendor M's
implementation (where `M' shall remain nameless :-) requires one to either
set some GUI toggle or else to include a #pragma just to get (draft)
standard conformant behavior.  That doesn't sound either reasonable or
user-friendly to me, but then I guess vendor `M' has its own customer
base, and its own reasons for making NON-standard conformant behavior
the default. :-(

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 8 Aug 1994 18:32:09 GMT
Raw View
In article <JASON.94Aug7160043@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
>
>>> Bzzt.  In the absense of any prior declaration of B, those code fragments
>>> are syntactically invalid; the grammar requires that 'B' be a
>>> 'class-or-namespace-name'.
>
>> OK.  So how about this:
>
>>  void (B::pmb)();
>>  class B { /* ... */ };
>
>> There.  Now surely you are not going to tell me that `B' is not the name
>> of a class in this translation unit!
>
>Nope.  I am going to tell you that `B' is not a class-name at that point.
>class-name is a syntactic category based on name lookup.  Since B has not
>been previously declared, no class is found, so `B' is lexed as a plain
>identifier.

Thank you for responding Jason.

I agree completely with your interpretation (of course) but I hope that
my *real* concern is now apparent.

Basically, I am concerned that the rules you have elaborated here (regarding
what it takes to get something to be a class-name) are nowhere elaborated
in the actual draft standard itself (and that we are thus all left to come
up with our own personalized interpretations in this area).

I may be wrong about the draft's lack of specificity in this case, but if
I am, I'd sure like to see the quotation (from the draft) which clearly
supports all of what you said (and what I agree MUST be the case).

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 9 Aug 1994 06:23:38 GMT
Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:

> Basically, I am concerned that the rules you have elaborated here (regarding
> what it takes to get something to be a class-name) are nowhere elaborated
> in the actual draft standard itself (and that we are thus all left to come
> up with our own personalized interpretations in this area).

1.4: X-name is a use of an identifier in a context that determines its meaning.

3.0: A name is a use of an identifier that denotes an entity or label.

Every name that denotes an entity is introduced by a declaration.
...
Some names denote types, classes or templates.  In general, it is necessary
to determine whether or not a name denotes one of these entities before
parsing the program that contains it.  The process that determines this is
called name lookup.

3.3.4:  A name declared outside all named namespaces, bocks and classes has
file scope.  The potential scope of such a name begins at its point of
declaration ...

I think that this text is adequate.

Jason




Author: gla@genua.ems.co.at (Gregor Glawitsch)
Date: 1 Aug 1994 07:12:37 GMT
Raw View
Walter E. Gillett (gillett@raisin-nut.ai.mit.edu) wrote:
: Hi, Folks
:     I've got the following test "program":

: class B;
: typedef void (B::*PMB)();

: It compiles just fine with g++ 2.5.8 but MSVCNT (Visual C++ for NT) complains:
: error C2644: basis class 'B' for pointer to member has not been defined

: I looked in the ARM but all I could find about forward class declaration is
: that you can't use such to define storage or a base-class.  From the ARM:

: class X;
: class Y : public X { // error: X undeclared  (I THINK the ARM means defined)
:     X a;  // error: X undeclared
:     static X b;  // ok: 'static X' is not a definition
: };


: So what gives?  Is there some part of the ARM that I missed that discusses
: this?  Is there some working paper blurb that does?  Or is MSVCNT broken?

Unfortunately, the compiler options of MS VC++ 1.1 default to disallowing
this. Simply set options-compiler-custom options c++ - representation method
to "General-purpose always". Voila.

----------------------------------------------------------------------------
Gregor Glawitsch           "Everybody should believe in something -
gla@ems.co.at               I believe I should have another beer."




Author: gillett@raisin-nut.ai.mit.edu (Walter E. Gillett)
Date: 29 Jul 1994 15:58:33 GMT
Raw View
Hi, Folks
    I've got the following test "program":

class B;
typedef void (B::*PMB)();

It compiles just fine with g++ 2.5.8 but MSVCNT (Visual C++ for NT) complains:
error C2644: basis class 'B' for pointer to member has not been defined

I looked in the ARM but all I could find about forward class declaration is
that you can't use such to define storage or a base-class.  From the ARM:

class X;
class Y : public X { // error: X undeclared  (I THINK the ARM means defined)
    X a;  // error: X undeclared
    static X b;  // ok: 'static X' is not a definition
};


So what gives?  Is there some part of the ARM that I missed that discusses
this?  Is there some working paper blurb that does?  Or is MSVCNT broken?
    Thanks for any help you can offer!
---------------------------------------------------------------
Joe Shapiro (NOT Walter Gillett, though I'm using his account!)
Please send replies to:                        joe@ConSolve.COM




Author: pickles@cnj.digex.net (Rose Hoskins)
Date: 30 Jul 1994 05:31:33 GMT
Raw View
Walter E. Gillett (gillett@raisin-nut.ai.mit.edu) wrote:
: Hi, Folks
:     I've got the following test "program":

: class B;
: typedef void (B::*PMB)();

: It compiles just fine with g++ 2.5.8 but MSVCNT (Visual C++ for NT) complains:
: error C2644: basis class 'B' for pointer to member has not been defined
: ...

: ---------------------------------------------------------------
: Joe Shapiro (NOT Walter Gillett, though I'm using his account!)
: Please send replies to:                        joe@ConSolve.COM
Joe,
 MSVC has a #pragma dealing with this situation.  The reason is
the representation of the porinter for this (near, far, ... that stuff).
You can add a pragma that will allow you to declare the Member-function-pointer
before its definition.

Hope this helps,
Michael S. Garnett
AT&T