Search code examples
c++listclassdata-structuresprivate-members

How do I fix my function definition that causes this error with my embedded class/struct: could not deduce template argument for 'T'?


I implemented a linked-list called Node that had a function called freeData where it would perform a delete on the node given and any following nodes.

I wanted to implement it inside my own custom list class as a private member, but came up with this error in Visual Studio 2019:

C2672 'freeData': no matching overloaded function found

C2783 'void custom::freeData(list::Node*&): could not deduce template argument for 'T'

I don't know what to change for my freeData function header to accept a Node* as an argument. I pass the argument pHead in these functions: ~list() and clear().

The previous definition before embedding freeData into the list class was void freeData(Node <T>* &pHead).

#include <iostream>

namespace custom
{

   template <class T>
   class list
   {
   public:
      list() : numElements(0), pHead(NULL), pTail(NULL) { }
      ~list() { freeData(pHead); }

      void clear() { freeData(pHead); numElements = 0; pHead = NULL; pTail = NULL; }

   private:
      struct Node;
      Node* pHead;
      Node* pTail;
      int numElements;
   };

   template <class T>
   struct list <T> :: Node
   {
      Node() : pNext(NULL), pPrev(NULL) {}
      Node(const T& t) : data(t), pNext(NULL), pPrev(NULL) {}

      T data;      // data of type T
      Node* pNext; // pointer to next node
      Node* pPrev; // pointer to previous node
   };

   template <class T>
   void freeData(typename list <T>::Node*& pHead)
   {
   }

} // end of namespace

int main()
{
   custom::list <int> l1;
   l1.clear();

   return 0;
}

Solution

  • freedata() is a free-standing function. Unlike class methods, free-standing functions have to be declared before they can be used. But, you can't forward-declare freedata() in this case since its argument depends on a type that needs to know what freedata() is. Catch-22.

    To fix that, you could break up the declarations and implementations of the list and Node class, eg:

    #include <iostream>
    
    namespace custom
    {
    
       template <class T>
       class list
       {
       public:
          list();
          ~list();
    
          void clear();
    
       private:
          struct Node
          {
             Node();
             Node(const T& t);
    
             T data;      // data of type T
             Node* pNext; // pointer to next node
             Node* pPrev; // pointer to previous node
          };
    
          Node* pHead;
          Node* pTail;
          int numElements;
       };
    
       template <class T>
       void freeData(typename list <T>::Node*& pHead)
       {
          ...
       }
    
       template <class T>
       list<T>::list() : numElements(0), pHead(NULL), pTail(NULL) { }
    
       template <class T>
       list<T>::~list() { freeData(pHead); }
    
       template <class T>
       void list<T>::clear() { freeData(pHead); numElements = 0; pHead = NULL; pTail = NULL; }
    
       template <class T>
       list<T>::Node::Node() : pNext(NULL), pPrev(NULL) {}
    
       template <class T>
       list<T>::Node::Node(const T& t) : data(t), pNext(NULL), pPrev(NULL) {}
    
    } // end of namespace
    
    int main()
    {
       custom::list <int> l1;
       l1.clear();
    
       return 0;
    }
    

    But really, there is no reason for freedata() to be a free-standing function in this example. It should be a member of the list class instead, eg:

    #include <iostream>
    
    namespace custom
    {
    
       template <class T>
       class list
       {
       public:
          list() : numElements(0), pHead(NULL), pTail(NULL) { }
          ~list() { clear(); }
    
          void clear() { freeData(pHead); numElements = 0; pHead = NULL; pTail = NULL; }
    
       private:
          struct Node
          {
             Node() : pNext(NULL), pPrev(NULL) {}
             Node(const T& t) : data(t), pNext(NULL), pPrev(NULL) {}
    
             T data;      // data of type T
             Node* pNext; // pointer to next node
             Node* pPrev; // pointer to previous node
          };
    
          Node* pHead;
          Node* pTail;
          int numElements;
    
          static void freeData(Node*& pHead)
          {
             ...
          }
       };
    
    } // end of namespace
    
    int main()
    {
       custom::list <int> l1;
       l1.clear();
    
       return 0;
    }