1
votes

I'm trying to implement a linked list. But I'm receiving an error when I try overloading the << operator. This is my program:

#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;

}

When i execute this code, the compiler gives me the following errors:

warning: friend declaration 'std::ostream& operator<<(std::ostream&, List*)' declares a non-template function [-Wnon-template-friend]

note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

Please help.

1
A warning is not an error. It indicates that the compiler thinks that something is ambiguous, and might not behave as expected. In this case, the friend declaration could either declare non-template function or a specialization of a function template - but in the latter case, a <> (or the explicit template arguments) would be missing (friend ostream& operator<< <>(/*..*/).dyp

1 Answers

1
votes

Since they take a class template argument, your friends need to be function templates, or specializations of function templates:

// function template friend
template <typename T2>
friend ostream& operator<<(ostream& out, const List<T2>& li);

Note that one would usually overload this operator to take a reference, not a pointer, as in the example above.

The drawback is that this is probably not restrictive enough: ostream& operator<<(ostream& out, const List<Widget>& li) would be a friend of List<int>. Since this is not usually the desired behaviour, you can provide a template specialization, which would restrict friendship to the same T as that with which the class is instantiated:

// function template, declared outside of the class:
template <typename T>
ostream& operator<<(ostream& out, const List<T2>& li);

// function template specialization, declared inside the class:
friend ostream& operator<< <>(ostream& out, const List<T>& li);