Nested class declaration: template vs non-template outer class
c++, forward-declaration, nested-class, templates
Solution
Why the compilation error?
The compiler needs to know the size of the member variable types in order to do object layout. For `Outer_1`, because `Inner` is simply a forward declaration, we don't know its size. Hence the compilation error. For `Outer_2` however, the definition is inline, so we know the size of it by the time we get to the member variable of type `Inner`.
Why do templates get a pass?
Class templates, on the other hand, don't get defined until template instantiation occurs. In your example, the implicit instantiation occurs in `main`. At that point, the definition of `Inner` is complete and therefore its size is known. We can see that this is the case by using explicit instantiation before the definition of `Inner`.
template<int d>
class Outer_t
{
public:
class Inner;
Inner i;
};
template class Outer_t<3>; // explicit instantation
template<int d>
class Outer_t<d>::Inner
{
public:
float x;
};
int main ()
{
Outer_t<3> o_t; // 3 or any arbitrary int
o_t.i.x = 1.0;
return 0;
}
Clang produces the following error:
a.cc:7:11: error: implicit instantiation of undefined member 'Outer_t<3>::Inner'
Inner i;
^
a.cc:10:16: note: in instantiation of template class 'Outer_t<3>' requested here
template class Outer_t<3>;
^
a.cc:5:11: note: member is declared here
class Inner;
^
The Solution
If you want to pull out the definition of the nested class, my suggested solution is to have it templatized just like `Outer_t`, but provide an alias for your convenience.
template <typename Dummy = void>
class Outer_1_Impl {
public:
class Inner;
Inner i;
};
template <typename Dummy>
class Outer_1_Impl<Dummy>::Inner {
public:
float x;
};
using Outer_1 = Outer_1_Impl<>;
int main () {
Outer_1 o1;
o1.i.x = 1.0;
}
Problem
I have a c++ template class that has a nested class inside, something like: ``` template<int d> class Outer_t { public: class Inner; Inner i; }; template<int d> class Outer_t<d>::Inner { public: float x; }; int main () { Outer_t<3> o_t; // 3 or any arbitrary int o_t.i.x = 1.0; return 0; } ``` This compiles without any problems. However, as soon as I declare a similar non-template class, something like this: ``` class Outer_1 { public: class Inner; Inner i; }; class Outer_1::Inner { public: float x; }; int main () { Outer_1 o1; o1.i.x = 1.0; return 0; } ``` I start getting the following error (I'm using gcc 4.6.3): "error: field ‘i’ has incomplete type". I know that I can remedy this by simply defining the inner class inline, inside the outer class: ``` class Outer_2 { public: class Inner { public: float x; }; Inner i; }; ``` This will compile, but I would like to avoid defining the nested class inline. So I have two questions: what is the reason for this apparently odd discrepancy between a template and non-template nested class declaration? And is there an elegant way to declare and use the nester class inside the outer class, while avoiding defining it inline, much in the same style as the template class? Thanks in advance for your help!