206

I have a class like so...

class Container {
public:
    class Iterator {
        ...
    };

    ...
};

Elsewhere, I want to pass a Container::Iterator by reference, but I don't want to include the header file. If I try to forward declare the class, I get compile errors.

class Container::Iterator;

class Foo {
    void Read(Container::Iterator& it);
};

Compiling the above code gives...

test.h:3: error: ‘Iterator’ in class ‘Container’ does not name a type
test.h:5: error: variable or field ‘Foo’ declared void
test.h:5: error: incomplete type ‘Container’ used in nested name specifier
test.h:5: error: ‘it’ was not declared in this scope

How can I forward declare this class so I don't have to include the header file that declares the Iterator class?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
bradtgmurray
  • 13,683
  • 10
  • 38
  • 36

3 Answers3

181

This is simply not possible. You cannot forward declare a nested structure outside the container. You can only forward declare it within the container.

You'll need to do one of the following

  • Make the class non-nested
  • Change your declaration order so that the nested class is fully defined first
  • Create a common base class that can be both used in the function and implemented by the nested class.
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    The common base class is the solution most used on my end. – Coyote Oct 03 '13 at 12:49
  • You can use friend to work around this, if you want. – Erik Aronesty Jun 14 '16 at 16:32
  • 9
    That's wrong: http://en.cppreference.com/w/cpp/language/nested_types – Nikerboker Jul 07 '17 at 08:30
  • 12
    @Nikerboker they are saying that nested classes cannot be forward declared _outside_ the container. The example in the link is forward declaring a nested class _inside the definition_ of the container, which is a different scenario. – Antonio Barreto Jan 02 '18 at 17:52
  • 6
    The fact that it is impossible to forward declare a nested structure outside the container seems like a limitation in C++, and something that should be possible. Right? Is there some reason why this is not possible? – HelloGoodbye Jan 04 '19 at 16:30
  • @HelloGoodbye I think the accessibility modifiers are the limitation: you wouldn't know where to place them (and whether you should be allowed to). – Wolf Jun 12 '19 at 13:28
  • 1
    @Wolf You've got a point there. Wouldn't it be possible to specify that by including the modifiers in the forward declaring expression? E.g. `class Container::(public Iterator)`, or something like that? (I'm not talking about the way the language is designed today, but about how it could theoretically be designed.) – HelloGoodbye Jun 12 '19 at 13:54
  • @HelloGoodbye I have the feeling that embedding declarations in classes are overrated. It's not comparable to declarations and definitions in namespaces even if the access via `::` looks similar. Maybe cases where programmers wish be allowed to forward declare a class within a class just arise from bad design. C++ as a language is already very abundent and its combinatorics seems to be overwhelming for the designers too ... I don't know if it would be a good idea to hope for this being estimated as a feature to add. – Wolf Jun 12 '19 at 14:41
  • @Wolf Late to the party, but: A class is, among other things, also a namespace, and for type declarations and static members I thought they are exactly comparable to the point of being functionally equivalent. – Peter - Reinstate Monica Dec 05 '19 at 11:11
  • @Peter-ReinstateMonica In C++, classes are *closed* whereas namespaces are *open*, and that seems to be an important difference. In comparison, C# has the concept of *partial* classes. I don't know if something like this is planned for the next C++ standards or if we should hope for it ;) – Wolf Dec 05 '19 at 11:31
  • Although unlikely to be the right solution, the forward declaration could also be avoided by using templates. – Jimmy T. Feb 23 '23 at 13:47
28

I don't believe forward declaring inner class of on an incomplete class works (because without the class definition, there is no way of knowing if there actually is an inner class). So you'll have to include the definition of Container, with a forward declared inner class:

class Container {
public:
    class Iterator;
};

Then in a separate header, implement Container::Iterator:

class Container::Iterator {
};

Then #include only the container header (or not worry about forward declaring and just include both)

Todd Gardner
  • 13,313
  • 39
  • 51
  • 30
    Good answer, except the part in the first-paragraph parenthesis. The "there is no way of knowing if there actually is an inner class" does not make sense in this context and is doubtful to be accurate. The whole point of a forward declaration is that you are telling the compiler that there is a class (or in this case, an inner class). That specific statement of yours would be just as true of normal classes and would mean you can't forward declare anything. – Loduwijk Nov 10 '16 at 20:28
3

I know of no way to do exactly what you want, but here is a workaround, if you are willing to use templates:

// Foo.h  
struct Foo
{
   export template<class T> void Read(T it);
};

// Foo.cpp
#include "Foo.h"
#include "Container.h"
/*
struct Container
{
    struct Inner { };
};
*/
export template<> 
  void Foo::Read<Container::Inner>(Container::Inner& it)
{

}

#include "Foo.h"
int main()
{
  Foo f;
  Container::Inner i;
  f.Read(i);  // ok
  f.Read(3);  // error
}

Hopefully, this idiom might be of some use to you (and hopefully your compiler is EDG-based and implements export ;) ).

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Faisal Vali
  • 32,723
  • 8
  • 42
  • 45