Search code examples
c++templatestemplate-specializationpartial-specialization

error: invalid use of incomplete type (Maybe a definition issue)


I've been struggling with this issue for a while and can't seem to get it right with all the templates and specializations. I think I'm missing a definition of the static function internal_set_BC but I'm not sure. When I compile the code below, I get the following error:

test.cc:37:49: error: invalid use of incomplete type ‘class RT<2, D>’
 static void RT<2, D>::internal_set_BC(D& d, T& t)
                                                 ^
test.cc:19:7: error: declaration of ‘class RT<2, D>’
 class RT: public BC<n, D>
       ^
test.cc:41:49: error: invalid use of incomplete type ‘class RT<3, D>’
 static void RT<3, D>::internal_set_BC(D& d, T& t)
                                                 ^
test.cc:19:7: error: declaration of ‘class RT<3, D>’
 class RT: public BC<n, D>

The simplified code is as follows:

class A {};
class B {};
class C {};
class E {};

template <int n>
class Base
{};

template <int n, typename D>
class BC: public Base<n>
{
public:
  virtual void set_BC(D& d, A& a) =0;
  virtual void set_BC(D& d, B& b) =0;
};

template <int n, typename D> 
class RT: public BC<n, D>   
{ 
public: 
  void set_BC(D& d, A& a)
  {internal_set_BC(d, a);}
  void set_BC(D& d, B& b)
  {internal_set_BC(d, b);}
private:
  template <typename T> 
  static void internal_set_BC(D& d, T& t);   
};

template <typename D, typename T>
static void RT<2, D>::internal_set_BC(D& d, T& t)
{//code
}
template <typename D, typename T>
static void RT<3, D>::internal_set_BC(D& d, T& t)
{//code
}

Moreover, when I try to instantiate internal_set_BC with this code:

template void RT<2, C>::internal_set_BC(C& d, A& t);

I get this error:

test.cc:45:51: error: explicit instantiation of ‘static void RT<n, D>::internal_set_BC(D&, T&) [with T = A; int n = 2; D = C]’ but no definition available [-fpermissive]
 template void RT<2, C>::internal_set_BC(C& d, A& t);

Which supports my suspicion of a missing definition I had on the above code.

Your help is highly appriciated.


Solution

  • You cannot. You can do such thing only for full specialization:

    template <>
    template <typename T>
    static void RT<2, int>::internal_set_BC(int& d, T& t)
    {//code
    }
    

    int is just example. You should write partial class specialization.

    template<typename D>
    class RT<2, D> : public BC<2, D>
    {
    // public functions set_BC.
    private:
       template <typename T>
       static void internal_set_BC(D& d, T& t);
    };
    
    template <typename D>
    template <typename T>
    void RT<2, D>::internal_set_BC(D& d, T& t)
    {//code
    }
    

    You can also write something like this, to specialize only internal_set_BC:

    template<int n, typename D, typename Impl>
    class RT_base : public BC<n, D>
    {
    public:
      void set_BC(D& d, A& a)
      {
         Impl::internal_set_BC(d, a);
      }
      void set_BC(D& d, B& b)
      {
         Impl::internal_set_BC(d, b);
      }
    };
    
    template <int n, typename D>
    class RT: public RT_base<n, D, RT<n, D> >
    {
       friend class RT_base<n, D, RT<n, D> >;
       template <typename T> 
       static void internal_set_BC(D& d, T& t);   
    };
    
    template<typename D>
    class RT<2, D> : public RT_base<2, D, RT<2, D> >
    {
       friend class RT_base<2, D, RT<2, D> >;
       template <typename T>
       static void internal_set_BC(D& d, T& t);
    };
    
    template <typename D>
    template <typename T>
    void RT<2, D>::internal_set_BC(D& d, T& t)
    {//code
    }
    

    or more simple, without CRTP

    template<int n, typename D>
    class RT_Base : public BC<n, D>
    {
    protected:
       template<typename T>
       static void internal_set_BC(D& d, T& t);
    };
    
    template<typename D>
    class RT_Base<2, D> : public BC<2, D>
    {
    protected:
       template <typename T>
       static void internal_set_BC(D& d, T& t);
    };
    
    template <typename D>
    template <typename T>
    void RT_Base<2, D>::internal_set_BC(D& d, T& t)
    {//code
    }
    
    template<int n, typename D>
    class RT : public RT_Base<n, D>
    {
    public:
      void set_BC(D& d, A& a)
      {
         this->internal_set_BC(d, a);
      }
      void set_BC(D& d, B& b)
      {
         this->internal_set_BC(d, b);
      }
    };