0

I just begin to learn C++ and I am now writing a C++ Program using class template.It realize some easy functions of a queue.But I get an error. The program concludes two files:Queue.h and Queue.cpp.Now I post my code. Queue.h:

#ifndef QUEUE_H
#define QUEUE_H

#include <iostream>
#include <cstdlib>
using namespace std;

template <class T> class QueueItem;

//define class template Queue
template <class Type>
class Queue{
public:
    Queue():front(0),back(0){}
    ~Queue();

    Type remove();
    void add(const Type&);
    bool is_empty() const{
        return front == 0;
    }

    friend ostream& operator<<(ostream&,const Queue<Type> &);

private:
    QueueItem<Type> *front;
    QueueItem<Type> *back;
};

//define class template QueueItem
template <class Type> 
class QueueItem{
public:
    QueueItem(const Type&t):item(t),next(0){}

    friend class Queue<Type>;

    friend ostream& operator<<(ostream&,const QueueItem<Type>&);
private:
    Type item;
    QueueItem *next;
};

template <class  Type>
Queue<Type>::~Queue()
{
    while(!is_empty())
        remove();
}

template <class Type>
void Queue<Type>::add(const Type &val)
{
    QueueItem<Type> *pt = new QueueItem<Type>(val);
    if (is_empty())
        front = back = pt;
    else
    {
        back ->next = pt;
        back = pt;
    }
}

template <class Type>
Type Queue<Type>::remove()
{
    if (is_empty())
    {
        cerr << "remove() on empty queue!"<<endl;
        exit(-1);
    }
    QueueItem<Type> *pt = front;
    front = front ->next;
    Type retval = pt ->item;
    delete pt;
    return retval;
}

template <class Type>
ostream& operator<<(ostream &os,const Queue<Type> &q)
{
    os << "<";
    QueueItem<Type> *p;
    for (p = q .front;p;p = p ->next)
    {
        os << *p << " ";
    }
    os << ">";

    return os;
}

template <class Type>
ostream& operator<<(ostream &os,const QueueItem<Type> &qi)
{
    os << qi.item;
    return os;
}

#endif

Queue.cpp:

#include "Queue.h"
#include <iostream>
using namespace std;

int main()
{
    //Queue<int> *p_qi = new Queue<int>;
    Queue<int> p_qi;
    cout << p_qi <<endl;

    for (int ival = 0;ival < 10;++ival)
    {
        p_qi .add(ival);
    }
    cout << p_qi <<endl;

    int err_cnt = 0;
    for (int ival = 0;ival < 10;++ival)
    {
        int qval = p_qi .remove();
        if (qval != ival)
            ++err_cnt;
    }
    cout << p_qi <<endl;

    if (!err_cnt)
        cout << "!!Queue executed OK!"<<endl;
    else
        cout << "??Queue errors:"<<err_cnt << endl;

    return 0;
}

But I get an error in Visual Studio 2008: 1>Queue.obj : error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class Queue const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Queue@H@@@Z),the symbolic is referenced in function _main 1>G:\CPPPrimer\Queue\Debug\Queue.exe : fatal error LNK1120: a unresolved external symbol

Could anyone tell me why? Thanks a lot.

I have resolved my problems.This is my code that runs on Visual Studio 2008 correctly:

#include <iostream>
#include <cstdlib>
using namespace std;

template <class Type> class QueueItem;

//类模板Queue的定义
template <class Type>
class Queue{
public:
    Queue():front(0),back(0){}
    ~Queue();

    Type remove();
    void add(const Type&);
    bool is_empty() const{
        return front == 0;
    }
    //将输出符号声明为函数模板
    template <class T>
    friend ostream& operator<<(ostream&,const Queue<T> &);

private:
    QueueItem<Type> *front;
    QueueItem<Type> *back;
};

//类模板QueueItem的定义
template <class Type> 
class QueueItem{
public:
    QueueItem(const Type&t):item(t),next(0){}

    friend class Queue<Type>;

    //将输出符号声明为函数模板
    template <class T>
    friend ostream& operator<<(ostream&,const QueueItem<T>&);

private:
    Type item;
public:
    QueueItem *next;
};


template <class  Type>
Queue<Type>::~Queue()
{
    while(!is_empty())
        remove();
}

template <class Type>
void Queue<Type>::add(const Type &val)
{
    QueueItem<Type> *pt = new QueueItem<Type>(val);
    if (is_empty())
        front = back = pt;
    else
    {
        back ->next = pt;
        back = pt;
    }
}

template <class Type>
Type Queue<Type>::remove()
{
    if (is_empty())
    {
        cerr << "remove() on empty queue!"<<endl;
        exit(-1);
    }
    QueueItem<Type> *pt = front;
    front = front ->next;
    Type retval = pt ->item;
    delete pt;
    return retval;
}

template <class Type>
ostream& operator<<(ostream &os,const Queue<Type> &q)
{
    os << "<";
    QueueItem<Type> *p;
    for (p = q .front;p;p = p ->next)
    {
        os << *p << " ";
    }
    os << ">";

    return os;
}

template <class Type>
ostream& operator<<(ostream &os,const QueueItem<Type> &qi)
{
    os << qi.item;
    return os;
}

int main()
{
    //Queue<int> *p_qi = new Queue<int>;
    //ostream& operator<<(ostream &os,const Queue<int>&);
    //ostream& operator<<(ostream &os,const QueueItem<int>&);
    Queue<int> p_qi;
    cout << p_qi <<endl;

    for (int ival = 0;ival < 10;++ival)
    {
        p_qi.add(ival);
    }
    cout << p_qi <<endl;

    int err_cnt = 0;
    for (int ival = 0;ival < 10;++ival)
    {
        int qval = p_qi .remove();
        if (qval != ival)
            ++err_cnt;
    }
    cout << p_qi <<endl;

    if (!err_cnt)
        cout << "!!Queue executed OK!"<<endl;
    else
        cout << "??Queue errors:"<<err_cnt << endl;

    return 0;
}
XiaJun
  • 1,855
  • 4
  • 24
  • 41
  • Literally a million duplicates of this one on SO... – Kerrek SB Feb 18 '12 at 01:40
  • possible duplicate of [C++ - LNK2019 error unresolved external symbol \[template class's constructor and destructor\] referenced in function _main](http://stackoverflow.com/questions/3705740/c-lnk2019-error-unresolved-external-symbol-template-classs-constructor-and) – ruakh Feb 18 '12 at 01:45

1 Answers1

1

You need to declare your operators first, as such :

template <typename Type> class Queue;
template <typename Type> class QueueItem;

template <typename Type>
ostream& operator<<(ostream &os,const Queue<Type> &q);

template <typename Type>
ostream& operator<<(ostream &os,const QueueItem<Type> &qi);

And the friend declarations need the template parameter :

friend ostream& operator<< <Type>(ostream&,const Queue<Type> &);
friend ostream& operator<< <Type>(ostream&,const QueueItem<Type> &);

This compiles, link and run under gcc and clang. Btw, QueueItem needs to have both operators as friend since the code for printing a queue also uses QueueItem members. On a personal note, I would suggest implementing const accessors and get rid of friends altogther.

François Moisan
  • 790
  • 6
  • 12
  • Thanks so much.I have solved this problem.The output symbolic "<<" should be declared as function template.And the class QueueItem member "next" should be declared public.This my code that runs on Visual Studio 2008 correctly. – XiaJun Feb 20 '12 at 11:05