-2

I cannot define a custom iterator over std::map<int,Foo> because Foo is an "incomplete type". What is wrong and how can I fix it so the custom iterator is defined correctly?

More specifically, I have a map object in another class Bar:

struct Bar{
  map<int,Foo> theMap;
 };

Note that struct Bar compiles fine, with no issues, in exactly the same file as the failed compile mentioned. If b is an object of type Bar, I would like to be able to write:

for (Foo& foo:b) {...code using "foo"...}

which would bind foo to each value in b.theMap. To do this, I defined a custom iterator that encapsulates theMap::iter like this:

struct myIterator{
  map<int,Foo>::iterator originalMapIterator;
  Foo& operator*(){return (*originalMapIterator).second;}
   ...operator++, operator== ,etc.
 }

But when struct myIterator is compiled, I get the error: "field has incomplete type 'Foo'" pointing to the map<int,Foo>::iterator .

I realize that I could probably fix this issue by changing the map to hold values of type unique_ptr(Foo) . Maybe that is best, although it is a fair amount of code (Foo is about 500 bytes). Anyway, is there a way to fix the definition as is? It seems odd that a map<int,Foo> is accepted fine by the compiler, but not a map<int,Foo>::iterator . Anyway, I want to understand just what is going on here.

As for "incomplete type": I am not certain exactly what this means here or how to avoid it. The Foo header file is included, what more would the compiler want? Why would it accept a map and not a map::iterator?

EDIT: I located the problem, see the answer.

kdog
  • 1,423
  • 11
  • 25
  • Try using `typename map::iterator`? –  Jun 24 '14 at 05:44
  • 1
    At the point where myIterator is being compiled, is Foo fully defined or just forward declared? It will need to be fully defined for the operators to compile since they use the iterator (or rather the std::pair which is returned by the iterator) – qeadz Jun 24 '14 at 05:46
  • Well, what is "fully defined"? It should be defined, the header file was included, I thought anyway. You know, I think I am just going to replace the map values by unique_ptr's, that' probably a cleaner way to handle the map anyway. Note that possibly the Foo.h uses a class that uses a class that uses Bar. – kdog Jun 24 '14 at 06:00
  • is `Foo` perhaps only forward declared? – Alexander Oh Jun 24 '14 at 06:05
  • Alex and qeadz are both right. I ran this through -E and found the error. I had these #ifndef things that were inhibiting my #includes inside deeply nested include headers. If one of you wants to make this an answer I will accept it, otherwise I will make this an answer. Surely I am not the first to run into this trap, so I will leave this question up there, with the suggestion: use g++ -E. – kdog Jun 24 '14 at 06:26
  • the solution would not to remove the `#ifdef`s but to avoid inclusion of everything everywhere, because that will lead to circular includes. Include only the headers that are really necessary where they are needed. Prefer forward declarations where they suffice and don't rely on indirect inclusion of needed headers. – Arne Mertz Jun 24 '14 at 06:41
  • You are correct Mertz. I eliminated unnecessary includes, which involved some refactoring including moving some header functions into cpp files, and being more careful about just what was included. That fixed the issue. – kdog Jun 24 '14 at 14:45

1 Answers1

0

As several commenters suggested, the culprit here was the class Foo was not actually defined, only forward declared. A series of #ifndef's and nested includes had shadowed the class definition. This was verified using the -E flag in the compiler to view the preprocessor output. Rewriting the code not to include unnecessary includes fixed the issue.

kdog
  • 1,423
  • 11
  • 25