Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a nested class can't have a member the type of which is the one of the enclosing class?

One of the methods of a class C needs to return a struct containing a pair of integers and a fresh instance of C. It may look awkward, but given the overall design, this makes a lot of sense (think of a Waveform class returning a range of itself as a copy, with the indication of where the range starts and ends).

The problem is that this doesn't seem to be allowed. I can redesign my class in order to circumvent this issue but can you explain me why, from the point of view of the compiler, this cannot be done

struct S {
    struct S2 {
        S s;
    };
};

as S is an incomplete type (this is the compiler error), and instead this is perfectly fine

struct C {
    struct C1 {
        C makeC() { return C(); }
    };
};

Where is a substantial difference?

like image 244
gd1 Avatar asked Feb 14 '23 06:02

gd1


2 Answers

At the point where you attempt to define S::S2, the type S is still an incomplete type, since its definition hasn't been completed yet. And class data members must have a complete type.

You can easily fix it like this:

struct S
{
    struct S2;   // declare only, don't define

    // ...
};

struct S::S2
{
    S s;         // now "S" is a complete type
};

It is essentially a design decision of C++ to not consider a type complete until the end of its definition. This prevents many pathological situations like the following example:

struct X
{
    struct Y { X a; };

    int b[sizeof(Y)];      // "sizeof" requires a complete type
};
like image 127
Kerrek SB Avatar answered Apr 08 '23 13:04

Kerrek SB


When you want to define a class you need a full definition of all the embedded (non-reference and non-pointer) members. While defining a class the class is not fully defined. That is, within a class definition the class under definition is merely declared, not defined.

That said, you can still have a member of your class in a nested class. You just need to define the nested class after the outer class is defined:

struct S {
    struct S2;
};

struct S::S2 {
    S s;
};

Since S is completely defined with the first closing braces, it can be used as embedded member after this point.

When you define a member function inside the class definition the definition is resolved as if it appears immediately after the class definition on the closest namespace level. That is, member function definitions know the fully defined class. The same doesn't apply to nested classes.

like image 44
Dietmar Kühl Avatar answered Apr 08 '23 13:04

Dietmar Kühl