Forward declaration of nested types/classes in C++
Solution 1
You can't do it, it's a hole in the C++ language. You'll have to un-nest at least one of the nested classes.
Solution 2
class IDontControl
{
class Nested
{
Nested(int i);
};
};
I needed a forward reference like:
class IDontControl::Nested; // But this doesn't work.
My workaround was:
class IDontControl_Nested; // Forward reference to distinct name.
Later when I could use the full definition:
#include <idontcontrol.h>
// I defined the forward ref like this:
class IDontControl_Nested : public IDontControl::Nested
{
// Needed to make a forwarding constructor here
IDontControl_Nested(int i) : Nested(i) { }
};
This technique would probably be more trouble than it's worth if there were complicated constructors or other special member functions that weren't inherited smoothly. I could imagine certain template magic reacting badly.
But in my very simple case, it seems to work.
Solution 3
If you really want to avoid #including the nasty header file in your header file, you could do this:
hpp file:
class MyClass
{
public:
template<typename ThrowAway>
void doesStuff();
};
cpp file
#include "MyClass.hpp"
#include "Annoying-3rd-party.hpp"
template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>()
{
// ...
}
But then:
- you will have to specify the embedded type at call time (especially if your function does not take any parameters of the embedded type)
- your function can not be virtual (because it is a template)
So, yeah, tradeoffs...
Solution 4
If you have access to change the source code of classes C and D, then you can take out class D separately, and enter a synonym for it in class C:
class CD {
};
class C {
public:
using D = CD;
};
class CD;
Solution 5
I would not call this an answer, but nonetheless an interesting find: If you repeat the declaration of your struct in a namespace called C, everything is fine (in gcc at least). When the class definition of C is found, it seems to silently overwrite the namspace C.
namespace C {
typedef struct {} D;
}
class A
{
public:
typedef struct/class {...} B;
...
C::D *someField;
}
class C
{
public:
typedef struct/class {...} D;
...
A::B *someField;
}
Related videos on Youtube
Calmarius
Languages I use often: C, PHP, JavaScript, HTML, CSS, MySQL. Languages I use less often: x86 assembly, C++, C# Technologies, formats I know well: x86 architecture, PE file format, ELF file format, OpenGL, OpenAL, SDL. (there may be items I forgot to put on the list.)
Updated on November 30, 2020Comments
-
Calmarius over 3 years
I recently got stuck in a situation like this:
class A { public: typedef struct/class {…} B; … C::D *someField; } class C { public: typedef struct/class {…} D; … A::B *someField; }
Usually you can declare a class name:
class A;
But you can't forward declare a nested type, the following causes compilation error.
class C::D;
Any ideas?
-
Johannes Schaub - litb almost 15 yearsWhy do you need that? Note that you can forward declare if it's a member of the same class being defined: class X { class Y; Y *a; }; class X::Y { };
-
Albert Wiersch over 7 yearsThis solution worked for me (namespace C { class D; };): stackoverflow.com/questions/22389784/…
-
bitlixi almost 6 yearsI found a solution link
-
-
Dolphin almost 15 yearsI tried this with cygwin gcc and it doesn't compile if you try to reference A.someField. C::D in the class A definition actually refers the the (empty) struct in the namespace, not the struct in the class C (BTW this doesn't compile in MSVC)
-
Calmarius almost 15 yearsIt gives the error: "'class C' redeclared as different kind of symbol"
-
Johannes Schaub - litb almost 15 yearsLooks like a GCC bug. It seems to think a namespace name can hide a class name in the same scope.
-
Marsh Ray over 12 yearsThanks for the answer. In my case, they're not my nested classes. I was hoping to avoid a huge library header file dependency with a little forward reference. I wonder if C++11 fixed it?
-
Xeo over 12 yearsIn C++11 you can inherit constructors by
using basename::basename;
in the derived class, thus no problem with complicated ctors. -
learnvst over 12 yearsOh. Just what I didn't want google to show up. Thanks anyway for the concise answer.
-
Naftali about 12 yearsWhat the heck is an
hpp
file? -
Maël Nison over 11 yearsSame here ... does someone know why it is not possible ? It seems there is valid use cases, and this lack prevents architecture consistency in some situations.
-
Alex Bitek over 11 yearslol, an .hpp header file is used in C++ projects to distinguish it from a C header file which typically ends with .h. When working with C++ and C in the same project some people prefer .hpp and .cpp for C++ files, to make it explicitly with what type of files their dealing with, and .h and .c for C files.
-
Artem Pisarenko over 8 yearsNice trick, but it will not work if pointer to IDontControl::Nested used within same header (where it forward declared) and accessed from external code which also includes full definition of IDontControl. (Because compiler will not match IDontControl_Nested and IDontControl::Nested). Workaround is to perform static cast.
-
Erik Aronesty almost 8 yearsYou can use friend. And just put a comment in that you're using it to work around the hole in C++.
-
SongWithoutWords over 7 yearsWhenever I encounter such needless flaws in this ersatz language, I am torn between laughing and crying
-
Mariusz Jaskółka about 5 yearsIt may work, but it is undocumented. The reason why it work is that
a::b
is mangled the same way, no matter ifa
is class or namespace. -
ridderhoff about 5 yearsI'd recommend doing the opposite and having the class outside, and just use
typedef
inside the class -
Dugi about 5 yearsDoesn't work with Clang or GCC. It says that the outer class was declared as something different than a namespace.