2

I am having a hard time understanding why a class can have an incomplete type static member of itself.

For example in my code below. Why is it allowed to have an incomplete type static member of itself inside class A, but the global static variable of class type B gets an error when it is an incomplete type?

class B {
public:
    B(int a) {
    }
};

static B test2; //error


class A {

public:
    static A test; //accepted

    A(int d) {
    }
};

Can someone explain to me perhaps what is going behind the scenes that gives the global static variable an error and why the static variable inside class A is accepted?

Kyle C
  • 107
  • 4
  • `B` is not incomplete at the declaration `static B test2;`. Did you make an error copying your example? It fails because of lack of a usable constructor, not incompleteness. – walnut Aug 25 '19 at 00:52
  • Are you mixing up "incomplete type" with "no matching constructor"? – Joseph Sible-Reinstate Monica Aug 25 '19 at 00:52
  • Yes perhaps I am mixing it up. My question should probably be why does the static variable in class A get to be an incomplete type instead of failing due to a lack of a usable constructor? – Kyle C Aug 25 '19 at 01:19

1 Answers1

6

Conflating a couple of dissimilar issues here

static B test2; //error

fails because B's constructor requires arguments that haven't been provided and is private so it can't be accessed outside the class. Correct those and B is good to go.

class B {
public: // added for outside access to constructor
    B(int a) {
        printf("%d\n", a);
    }
};

static B test2{1}; // added arguments

As for A, a static member is not part of a class instance, so the compiler doesn't need it to be complete. It doesn't take up any space, and at this point it's not being used for anything. It's just a declaration. You can declare all sorts of stuff without the compiler getting upset (so long as the declaration's syntax is good). You run into trouble when you try to use something without a definition.

Example:

void testfunc(const A &)
{

}

int main(){
    testfunc(A::test);
}

fails at the linker because A::test was never defined. If you try to correct that with

class A {

public:

    static A test{1}; // let's try to define it inline!
    int a;
    int b;
    int c;

    A(int d, int e) : a(d), b(e), c(15) {

    }

    A(int d) :A(d, 10) {
        printf("%d %d %d", a, b, c);
    }
};

now the compiler cares enough to report that the class is incomplete. We'll have to move the definition outside the class where it is complete

class A {

public:

    static A test; //declared
    int a;
    int b;
    int c;

    A(int d, int e) : a(d), b(e), c(15) {

    }

    A(int d) :A(d, 10) {
        printf("%d %d %d", a, b, c);
    }
};
A A::test{1}; // defined

Now

void testfunc(const A &)
{

}

int main(){
    testfunc(A::test);
}

will compile and link.

Documentation on the care and feeding of static members.

user4581301
  • 29,019
  • 5
  • 26
  • 45
  • I liked your answer and it answered some questions, but why does "test2" need arguments for a constructor while "test" inside class A does not need arguments for a constructor when declared? Thanks – Kyle C Aug 25 '19 at 02:02
  • `static B test2;` is trying to define a variable that is an instance of a class. The program needs to construct this instance, so you have to provide the necessary arguments. `static A test;` is a declaration. Declarations just mean that the variable, function, type, or whatever exists. It doesn't make one. In a class, a `static` member variable is a declaration. Sometimes you can define the `static` member by initializing it in the class, but this is not one of those times. – user4581301 Aug 25 '19 at 02:17
  • Recommended reading: [What is the difference between a definition and a declaration?](https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration) – user4581301 Aug 25 '19 at 02:18