In test.h
:
#ifndef TEST_H
#define TEST_H
#include <map>
struct Incomplete;
class Test {
std::map<int, Incomplete> member;
public:
Test();
int foo() { return 0; }
};
#endif
In test.cpp
:
#include "test.h"
struct Incomplete {};
Test::Test() {}
In main.cpp
#include "test.h"
int main() {
Test test;
return test.foo();
}
g++ 4.7 gives me an error that struct Incomplete
is forward declared when I write g++ main.cpp test.h -o main.o
.
However, if I change std::map<int, Incomplete> member
to std::map<int, Incomplete*> member
, main.o
compiles. Why is this?
Note: as of C++11, the explanation below is outdated: standard library containers now work with incomplete types.
Why is this?
Because the C++ standard library containers are not defined to work with incomplete member types. This is by design1 – but it’s arguably an error (and might be changed in future versions of C++). The Boost.Containers library fixes this.
Your code with pointers works because a pointer to an incomplete type is itself a complete type. However, this obviously changes the semantics of your type quite drastically (in particular, who manages the memory?) and it’s generally not a good idea to use this as a replacement.
1 It’s worth pointing out that the article claims that you technically cannot implement std::map
to work with incomplete types. However, this claim is wrong.