Search code examples
c++templatesvariadic-templatescrtp

g++ thinks my class declaration is a "forward declaration"


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.


Solution

  • 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.