1

This is not allowed as test will be infinitely big (it contains itself recursively).

struct test{
 test t;
};

However the following compiles fine:

struct test{
 int get(test t1);// or `int get(test t1){}`
 static test t2;
};

How does it know how much space to allocate for t1 on the stack, at that point test isn't complete yet. Same question goes for t2 and it's location on static memory.

Dan
  • 2,694
  • 1
  • 6
  • 19
  • Does this answer your question? [Incomplete types in member function definitions](https://stackoverflow.com/questions/57631441/incomplete-types-in-member-function-definitions) – François Andrieux Jan 12 '22 at 14:16
  • @FrançoisAndrieux no that's different. He's not showing any definitions here. And that's the actual point. He's declaring, not defining. – JHBonarius Jan 12 '22 at 14:19
  • The very informal answer is that your question is based on a mistaken assumption. The compiler doesn't need to know the size (or anything else) at that point, so it's not a problem. – molbdnilo Jan 12 '22 at 14:27

2 Answers2

4

Case 1

Here we consider the statement static test t2;

From static documentation:

The declaration inside the class body is not a definition and may declare the member to be of incomplete type (other than void), including the type in which the member is declared:

struct S
{
   
   static S s;     // declaration, incomplete type (inside its own definition)
};

For the exact same reason your statement static test t2; is allowed/valid.

Case 2

Here we consider int get(test t1);

The above statement is a member function declaration and not a definition so this is also valid. That is, since it is a function declaraion you can use the incomplete type as parameter.

Case 3

Here we are considering:

int get(test t1){}

This works because:

The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    your explanation for 2 is moot, because a definition is fine as well https://godbolt.org/z/dY4WjbbvE – 463035818_is_not_an_ai Jan 12 '22 at 14:21
  • 1
    I don't think this is fully right. `int get(test t1){}` also compiles. – Dan Jan 12 '22 at 14:21
  • @Dan The answer is correct and answers the question that was actually asked, but it begs the question of why a definition also works, which is an entirely different case related to phases of translations. See the question I linked in the comment for information on *that* case. – François Andrieux Jan 12 '22 at 14:22
  • 1
    I've added a comment. Please also add why the definition is allowed. – Dan Jan 12 '22 at 14:25
  • @Dan working on it. – Jason Jan 12 '22 at 14:26
  • 1
    @FrançoisAndrieux went over it. I believe the could answer it too? stackoverflow.com/a/4368807 – Dan Jan 12 '22 at 14:29
  • @Dan _"I don't think this is fully right. `int get(test t1){}` also compiles."_ yes, but that's a separate thing and not what you are asking. The answer is right for what you are asking. Not everything is connected, or an answer would always be the complete C++ standard. – JHBonarius Jan 12 '22 at 14:33
  • @JHBonarius The question was edited. – François Andrieux Jan 12 '22 at 14:34
  • @Dan Can you ask a separate question for why the definition works. I think my current answer answers your original question. Also, you have edited your question(by adding the why definition works) such that it changes the intent of the original question to which my answer was based. So kindly ask a separate question for the definition case. – Jason Jan 12 '22 at 14:35
  • 1
    @FrançoisAndrieux he edited the question 4 minutes after he wrote the comment. For some reason my comment was added delayed. Anyhow, adding more questions in a question after the question is already answered by multiple people is not really desired in SO IMHO. It invalidates the answers, wasting peoples effort... – JHBonarius Jan 12 '22 at 14:38
  • 1
    How would I know declaration or definition would make a difference in this case? Please answer it all here now I have added a comment. – Dan Jan 12 '22 at 14:43
  • @Dan I have added why the definition works at the end of my answer. Check it out. – Jason Jan 12 '22 at 15:01
  • 1
    Here's the part I still don't get. in `int get(test t1){}` the compiler needs to emit code to allocate space on the stack for `t1`, but it can't yet know how much space it needs, so how would this work? – Dan Jan 12 '22 at 15:03
  • 1
    @Dan For that you should ask a separate question. – Jason Jan 12 '22 at 15:05
2

One thing to note is that neither member functions nor static members affect the size of an object of a class. Functions are not reflected in object size.

You can have as many functions as you want and the class size will not change. The compiled code for the functions is stored in the "code" segment of memory.

Static data is also not stored in individual objects. No matter how many objects of class test you will have, the static data will remain the same size.

Since these declarations do not affect the size of test, it should be no problem for a compiler to delay finishing them until after the completion of the definition of test.

Gonen I
  • 5,576
  • 1
  • 29
  • 60
  • though the quesiton is: Why is it fine to use `test` before its definition is complete – 463035818_is_not_an_ai Jan 12 '22 at 14:19
  • Interesting. I see the following question "How does it know how much space to allocate for t1 on the stack, at that point test isn't complete yet." – Gonen I Jan 12 '22 at 14:21
  • Maybe this could explain why it can be used on itself? https://stackoverflow.com/a/4368807 – Dan Jan 12 '22 at 14:22
  • yes, but the size is only known once the definition is complete while the `t1` appears in the definition – 463035818_is_not_an_ai Jan 12 '22 at 14:22
  • But the answer to "How does it know how much space to allocate for t1 on the stack, at that point test isn't complete yet." isn't that member functions and static members don't change the size. The answer to that is that it's fine for the type to be incomplete in that context. – François Andrieux Jan 12 '22 at 14:25