Topic: Defining members of class T within class T
Author: doug@monet.ads.com (Doug Morgan)
Date: 1995/08/07 Raw View
In article <3vm5c5$7nm@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:
> In article 950729200137683@wem.org, henry.baker@wem.org (Henry Baker) writes:
> >
> >Suppose I have the following nested class:
> >
> >struct pair
> >{struct pair_rep
> > {pair car,cdr;}; // inner class has member of outer class.
> > pair_rep *rep;};
> >
> >I understand the rule saying that a class cannot be a member of itself
> >[Stroustrup#2, page 545] (Bertrand Russell is now spinning in his grave ;-),
> >but I'm having trouble understanding why a _nested_ class cannot have a
> >member
> >of the outer class being defined. This is especially irritating, since the
> >above is capable of being rewritten as [Stroustrup#2, page 645]:
> >
> >struct pair
> >{struct pair_rep;
> > pair_rep *rep;};
> >
> >struct pair::pair_rep
> >{pair car,cdr;};
> >
> >Are compiler writers just being lazy, or what??
>
> It isn't a compiler issue specifically. The language rule is that you
> can't define a class member having an incomplete type. At the point
> where struct pair_rep is defined, type 'pair' is an incomplete type,
> yet its definition is required as part of the definition of type pair_rep.
That's not quite the correct language rule for this case. The
language rule is 9.2(7): "Non-static (9.5) members that are class
objects shall be objects of previously defined classes. In
particular, a class cl shall not contain an object of class cl, but it
can contain a pointer or reference to an object of class cl. When an
array is used as the type of a nonstatic member all dimensions shall
be specified."
The rules about incomplete types (in 3.9) deal with: "No objects shall
be defined with incomplete types." Defining an object is completely
different from defining a class that has a data member that is a class
object. Thus, arguments invoking incomplete types are irrelevant to
the problem with Baker's first version.
The real question is what exactly constitutes "previously defined
classes" in 9.2(7). It is basically an undefined term, except through
the "in particular..." we know it includes the specific class being
declared/defined. Whether it includes enclosing classes is almost
open to interpretation, except for the example you give below gives a
strong indication that enclosing classes are not included (and
therefore compiler writers are not just being lazy).
>
> When you split the definition from the declaration as in the second
> example, you no longer have the problem.
>
> To better understand the rule, suppose that the first version were legal
> but we modified the definition slightly (and reformat to make it readable):
>
> struct pair { // 3rd version
> struct pair_rep {
> pair car, cdr;
> };
> pair_rep pr;
> };
>
> Clearly version 3 isn't valid, yet up to the end of the inner struct
> definition it is identical to the original.
Excellent point. As written, WP only rules out this invalid version
if the "previously defined classes" do not include the enclosing
classes. Too bad, but that's the restricted interpretation that
invalidates the 3rd version.
> How much re-parsing and
> re-defining on the fly should a compiler be required to do?
All that is necessary to sort out an implicit DAG of class layout
specifications (and detect any invalid cycles) would be the answer
users would like to hear. However, that seems to be more than C++
requires.
> The actual
> rule of requiring complete types where a complete type is needed allows
> early determination of errors, instead of arbitrary amounts of re-checking.
Again, complete types aren't the issue. Rather, it is what are
"previously defined classes." Given that change, your conclusion
remains essentially correct (though, the work necessary to set up a
dependency structure, verify that it is a DAG, and complete the
compilation does not involve completely _arbitrary_ amounts of
re-checking).
Doug
----------
Doug Morgan
doug@ads.com (UNIX)
morgan_doug@smtpmac.bah.com (MS-Mail)
TEL: (415) 960-7444
FAX: (415) 960-7500
Booz-Allen & Hamilton, Inc.
1500 Plymouth St.
Mountain View, CA 94043-1230
----------
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/08/01 Raw View
In article 950729200137683@wem.org, henry.baker@wem.org (Henry Baker) writes:
>
>Suppose I have the following nested class:
>
>struct pair
>{struct pair_rep
> {pair car,cdr;}; // inner class has member of outer class.
> pair_rep *rep;};
>
>I understand the rule saying that a class cannot be a member of itself
>[Stroustrup#2, page 545] (Bertrand Russell is now spinning in his grave ;-),
>but I'm having trouble understanding why a _nested_ class cannot have a
>member
>of the outer class being defined. This is especially irritating, since the
>above is capable of being rewritten as [Stroustrup#2, page 645]:
>
>struct pair
>{struct pair_rep;
> pair_rep *rep;};
>
>struct pair::pair_rep
>{pair car,cdr;};
>
>Are compiler writers just being lazy, or what??
It isn't a compiler issue specifically. The language rule is that you
can't define a class member having an incomplete type. At the point
where struct pair_rep is defined, type 'pair' is an incomplete type,
yet its definition is required as part of the definition of type pair_rep.
When you split the definition from the declaration as in the second
example, you no longer have the problem.
To better understand the rule, suppose that the first version were legal
but we modified the definition slightly (and reformat to make it readable):
struct pair { // 3rd version
struct pair_rep {
pair car, cdr;
};
pair_rep pr;
};
Clearly version 3 isn't valid, yet up to the end of the inner struct
definition it is identical to the original. How much re-parsing and
re-defining on the fly should a compiler be required to do? The actual
rule of requiring complete types where a complete type is needed allows
early determination of errors, instead of arbitrary amounts of re-checking.
---
Steve Clamage, stephen.clamage@eng.sun.com