Forward declarations of unnamed struct
Bounty question: So, these two Foo
s aren't the same thing. Fine. The second form is given in a library. How do I forward-declare it given that I can't change it?
I always thought C and C++ allowed repeated declarations provided that there were no repeated definitions. Then I came across this problem when trying to write C++ code which extends a C library.
struct Foo;
typedef struct {} Foo;
This gives the following error:
'struct Foo' has a previous declaration as 'struct Foo'
I want to forward-declare, darn it! What's wrong here?
typedef-ing anonymous struct is a practice that pre-dates C++03 and is mainly oriented to retain compatibility with pre-C99 compilers.
Given that this is 2011, and that both C++ and C are changed, I wonder why there is no more up-to-date version of such a library!
If it is not in development anymore, you cannot "leave", but just "survive" and change it is the way to do that. If still in deployment, submit the issue to the development team.
If you need a workaround, consider that struct can inherit. So, write a forward declaration like
struct MyFoo;
and define it as
#include "old_library.h"
struct MyFoo: public Foo {};
And in all your code, forget about Foo
and always use MyFoo
.
You're declaring two different entities with the same name. The first, struct Foo
, is a struct named Foo
. The second is an alias for an anonymous struct.
If you do instead:
struct Foo;
struct Foo {};
It works, because you're declaring a struct named Foo
in both situations.
You cannot forward declare anonymous structs. You're left with two choices: include the whole definition, or change the header and name the struct.
In a similar situation, I have a legacy C header with something like
== old_library.h ==
typedef struct { int data; } Foo;
== /old_library.h ==
I use it in a C++ class of my own, as parameter for a private method:
class C {
void run(Foo *ds);
...
}
To avoid #include "old_library.h" from C.hpp, I use the following forward declaration:
class C {
struct Foo;
void run(Foo *ds);
...
}
and in C.cpp I have the following statements:
extern "C" {
#include "old_library.h"
}
struct C::Foo : public ::Foo {};
This way, I use C::Foo instead of Foo transparently, and don't need a MyFoo!
You don't need to typedef structs in C++:
struct Foo; // Forward declaration
struct Foo
{
}; // Definition
If you want to call it just Foo
instead of struct Foo
in C, you do need the typedef, which can also be done in different ways:
struct Foo; /* Forward declaration */
struct Foo /* The name is needed here */
{
}; /* Definition */
typedef struct Foo Foo; /* typedef */
or
struct Foo; /* Forward declaration */
typedef struct Foo /* The name is needed here */
{
} Foo; /* Definition and typedef combined */
You can of course use the form struct Foo
in both C and C++.
Your forward declaration declares that there will be a struct
called Foo
.
Your second declaration is of a typedef
called Foo
. These are not the same thing.