Stripped down to the bare minimum, here's the code I'm trying to compile:
template<class T>
class B
{
protected:
std::vector<typename T::I> v;
public:
template<class... Args>
void add(Args... args )
{
this->v.emplace_back(std::forward<Args>(args)...);
}
typename T::I get(int i)
{
return this->v[i];
}
};
class D : public B<D>
{
public:
typedef std::string I;
};
If I instantiate D
and try to compile this in g++
, it complains:
error: invalid use of incomplete type ‘class D’
std::vector<typename T::I> v;
and adds a note,
note: forward declaration of ‘class D’
class D : public B<D>
If I try clang++
instead, I get a different error:
error: no type named 'I' in 'D'
std::vector<typename T::I> v;
I'm sure I'm just doing something silly here but I can't seem to figure it out.
The problem is just that when you write
class D : public B<D>
you pass the class D
as template parameter of B
when D
is still incomplete.
So the compiler can't see D::I
because isn't defined at this point.
g++ explicitly say this: "error: invalid use of incomplete type ‘class D’".
clang++ dosn't say this explicitly but doesn't find I
for this reason.
-- EDIT --
The OP asks
How do you do what I want to do, then?
The only solution that I see (not a great solution, unfortunately) is define what you need in B
in another class/struct, say C
struct C
{ using I = std::string; };
and inherit D
from C
and B<C>
class D : public C, public B<C>
{ };
This way C
is fully defined, when you use it as template parameter for B
, and also inherited from D
.