Перегрузка оператора << в C ++ при использовании шаблонов в программе со связанным списком

Я пытаюсь реализовать связанный список. Но я получаю сообщение об ошибке при попытке перегрузить оператор <<. Это моя программа:

#include<iostream>
#include<stdlib.h>
using namespace std;

template<class T> class List;

template<class T>
class Node
{
    T data;
    Node* next;
    public:
        Node(T val)
        {
            data = val;
            next = NULL;
        }
        Node(T val, Node* link)
        {
            data = val;
            next = link;
        }
        friend class List<T>;
        friend ostream& operator<<(ostream& out, List<T>* li);
};

template<class T>
class List
{
    Node<T>* first;
    Node<T>* last;
    public:
        friend ostream& operator<< (ostream& out, List<T>* li)
        {
            if(li->first)
                out<<"Empty.\n";
            else
            {
                out<<"Displaying: \n";
                Node<T>* p = li->first;
                while(p)
                {
                    out<<p->data;
                    p = p->next;
                }
            }

            return out;
        }
        List()
        {
            first = last = NULL;
        }
        List(T val)
        {
            Node<T>* l = new Node<T>(val);
            first = last = l;
        }
        void insertHead(T val)
        {
            if(first)
            {
                Node<T>* p = new Node<T>(val,first);
                first = p;
            }
            else
                first = last = new Node<T>(val);
        }
        void insertTail(T val)
        {
            if(first)
            {

                last->next = new Node<T>(val);
                last = last->next;
            }
            else
                first = last = new Node<T>(val);
        }
        void insertAt(T val, int pos)
        {
            //check if list is empty.
            if(first==NULL)
                first = new Node<T>(val);
            else
            if(pos==1)
                insertHead(val);
            else
            {
                Node<T>* curr = first;
                int i = 1;
                // iterate till position is reached.
                while( i<pos )
                {
                    curr=curr->next;
                    i++;
                }
                //create new node.
                Node<T>* p = new Node<T>(val,curr->next);
                //link new node to previous node.
                curr->next = p;
            }
        }
        void concatenate(List<T>* m)
        {
            //m is concatenated to end of *this.
            if(first)
            {
                last->next = m->first;
                last = m->last;
            }
            else
            {
                first = m->first;
                last = m->last;
            }
            m->first = m->last = 0;
        }
        void delVal(int pos)
        {
            //if position is first, delete first node.
            if( pos == 1 )
            {
                Node<T>* p = first;
                first = first->next;
                if(first==0)
                    last=0;

                free(p);
            }
            //otherwise, iterate till correct position and delete the node.
            else
            {
                int i = 1;
                Node<T>* curr = first;
                while( i<pos )
                {
                    curr = curr->next;
                    i++;
                }
                Node<T>* p = curr->next;
                curr->next = p->next;
                if(curr->next==0)
                    last = curr;
                free(p);
            }
        }

        void searchVal(T val)
        {
            Node<T>* curr = first;
            int i = 0;
            cout<<"Search: ";
            while( curr )
            {
                if( curr->data==val )
                {
                    cout<<val<<" found at position "<<i<<endl;
                    break;
                }
                else
                {
                     curr=curr->next;
                     i++;
                }
            }
            cout<<endl;
        }
        void recDisplay(Node<T>* curr)
        {

            if(curr!=0)
            {
                cout<<curr->data<<endl;
                recDisplay(curr->next);
            }

        }

        void Display()
        {
            cout<<"Displaying: \n";
            recDisplay(first);
        }
        void Reverse()
        {
            Node<T>* curr = first;
            Node<T>* prev = 0;
            while( curr )
            {
                Node<T>* r = prev;
                prev = curr;
                curr = curr->next;
                prev->next = r;
            }
            first = prev;
        }
        ~List()
        {
            Node<T>* p = first;
            cout<<"Deleting:"<<endl;
            while(first!=0)
            {
                free(first);
                first = p->next;
                p = first;
            }
        }
};



int main()
{
    List<int>*  l = new List<int>();
    l->insertHead(5);
    l->insertTail(6);
    l->insertTail(7);
    cout<<l;

}

Когда я выполняю этот код, компилятор выдает мне следующие ошибки:

предупреждение: объявление друга 'std :: ostream & operator << (std :: ostream &, List *)' объявляет не шаблонную функцию [-Wnon-template-friend]

примечание: (если это не то, что вы хотели, убедитесь, что шаблон функции уже объявлен и добавьте <> после имени функции здесь)

Пожалуйста помоги.

Ответы на вопрос(1)

Ваш ответ на вопрос