invalid use of incomplete type 'struct a'

This is a discussion on invalid use of incomplete type 'struct a' within the C++ Programming forums, part of the General Programming Boards category; Hi to all, I m quite new to c++ and i try to compile this little program without success...
Code:
...

The return type of main is int, not void, meaning it also needs a return value.

I don't think there is a good way to do what you want here. Why? Because of some stupidity in the design of C++: for reasons of "safety", you cannot use a void* (or any other kind of pointer) generically the way you can in C. Your forward declarations of a and b are incomplete, but if you complete them, b will contain a reference to an undefined type.

So the trade-off for safety is dysfunction and awkwardness in this case. Sorry. You might be able to get out of it by making aa a static variable of a template function in b, since that function will only need a prototype in b's declaration (no reference to a). Actually that's not allowed either, template functions need to be defined in the declaration. Sorry again.

I don't think there is a good way to do what you want here. Why? Because of some stupidity in the design of C++: for reasons of "safety", you cannot use a void* (or any other kind of pointer) generically the way you can in C. Your forward declarations of a and b are incomplete, but if you complete them, b will contain a reference to an undefined type.

I do not know what exactly does ajoqiqu want to do here, but there may be an obvious solution: define the member functions of b after the definition of a.

In fact, this solution is applicable to C: you would define functions that require the definition of a struct after the struct definition is in scope. It seems to me that once you come across something that you see as a "stupidity in the design of C++" (and as far as I can tell the premise of your rant is inaccurate to begin with), your mind goes blank and you forget even those techniques that can be carried over from C.

EDIT:
Beyond this, ajoqiqu: are you are of the so-called rule of 3? That is, when you need to define a destructor yourself (other than trivially to declare it virtual), you typically need to declare the copy constructor and copy assignment operator?

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

I don't think there is a good way to do what you want here. Why? Because of some stupidity in the design of C++: for reasons of "safety", you cannot use a void* (or any other kind of pointer) generically the way you can in C. Your forward declarations of a and b are incomplete, but if you complete them, b will contain a reference to an undefined type.

So the trade-off for safety is dysfunction and awkwardness in this case. Sorry. You might be able to get out of it by making aa a static variable of a template function in b, since that function will only need a prototype in b's declaration (no reference to a). Actually that's not allowed either, template functions need to be defined in the declaration. Sorry again.

Actually you can MK; look up static_cast<somePtrType>(void *argument)...anytime you have to interact with the pthread environment you need to do something like this and C++ likes it just fine:

The segfault has an identical cause too: a sort of infinitely recursive memory corruption (backtrace for your code):

#0 _int_malloc (av=0x7ffff7633a00, bytes=<value optimized out>)
at malloc.c:4130
#1 0x00007ffff7342a08 in __libc_malloc (bytes=8) at malloc.c:3551
#2 0x00007ffff7b981ed in operator new (sz=8)
at ../../../../libstdc++-v3/libsupc++/new_op.cc:57
#3 0x0000000000400859 in a (this=0xa006b0) at test2.cpp:20
#4 0x0000000000400716 in b (this=0xa00690) at test2.cpp:37
#5 0x0000000000400866 in a (this=0xa00670) at test2.cpp:20
#6 0x0000000000400716 in b (this=0xa00650) at test2.cpp:37
#7 0x0000000000400866 in a (this=0xa00630) at test2.cpp:20
#8 0x0000000000400716 in b (this=0xa00610) at test2.cpp:37
#9 0x0000000000400866 in a (this=0xa005f0) at test2.cpp:20
#10 0x0000000000400716 in b (this=0xa005d0) at test2.cpp:37
#11 0x0000000000400866 in a (this=0xa005b0) at test2.cpp:20

[...etc]

Perhaps the reason is sort of obvious Not even a void* will save this logical flaw.

The segfault has an identical cause too: a sort of infinitely recursive memory corruption (backtrace for your code):

Ah, but it is precisely because the members are pointers that, in a more fully developed class, one of the members could be a null pointer, thus ending this "infinitely recursive" problem, as how one might do it with a linked list implementation. As it stands, my example simulates the otherwise impossible situation of having a member of a class that has as a member an object of the current class. This is hardly a problem with the design of C++. It is a question of what ajoqiqu wants to do.

Originally Posted by MK27

Hmm, can you use that to cast to an object too? I presume so...FoundationThreadBase is a class, no?

Yes, you can. You can freely cast a pointer to an object to a pointer to void* and back.

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

Ah, but it is precisely because the members are pointers that, in a more fully developed class, one of the members could be a null pointer, thus ending this "infinitely recursive" problem, as how one might do it with a linked list implementation. As it stands, my example simulates the otherwise impossible situation of having a member of a class that has as a member an object of the current class. This is hardly a problem with the design of C++. It is a question of what ajoqiqu wants to do.

Yes, you can. You can freely cast a pointer to an object to a pointer to void* and back.

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

The real problem and one that can be solved in C++ is an incorrect use of the langugage. Had the implementation of said classes been in a separate file then the forward declare would have worked fine. You can forward declare anything you want so long as you don't actually use the class you are forward declaring. So if A needs B and B needs A and A has both a header and an impl and B has both a header and an impl the forward declare works just fine. The problem arises from this section:

The pointer aa is fine b/c after all it's really just 4 bytes. The type is a compiler side feature but in the end it is still just 4 bytes. However the constructor for b is where the problem is.
How can the compiler instantiate aa when a has not been fully declared? class a is incomplete and therefore that line of code will generate the error that you received. As well there is no reason to forward declare b since b is declared fully prior to a. The only problem here is an incorrect use of the language and it is not related to any pointer problems or fundamental problems in the design of C++.

Had b had a header where a was forward declared and b had an impl where a was included and used this would have worked just fine. Plain and simple you cannot use (read: instantiate) a class you have not fully declared.

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.