1

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<< <>(/*..*/). Commented Sep 15, 2013 at 17:15

1 Answer 1

1

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);
Sign up to request clarification or add additional context in comments.

14 Comments

Maybe I'm just confused, but why do they need to be templates?
@DyP it takes a class template as argument, so it needs to be a function template if you want it to work for all List<T>. The fact that it is declared inside a class template does not make it a function template.
@DyP whats the point of your question? is not that overload must be a template to let the compiler infer the type used in the list?
@juanchopanza List<T> is not a class template, it's a specialization, therefore a type.
It.. doesn't even need to be a template. Every specialization of List<T> could define an overload of operator<< for its specific type.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.