Ошибка ссылки при использовании функции друга в шаблоне списка ссылок - PullRequest
3 голосов
/ 17 декабря 2011

Я запрограммировал список связанных шаблонов (в файле .h) и получил ошибку ссылки.

template <typename T>
class LinkedList
{
private:
    Node<T>* head;
    Node<T>* tail;
    int size;

public:
    LinkedList();
    ~LinkedList();
    inline T* Front() {return &(this->head);};
    inline const T* Front() const {return (const T*)this->head;};
    void InsertFirst(const T&);
    void InsertLast(const T&);
    void RemoveFirst();
    void RemoveLast ();
    void RemoveItem (const T&);
    void Sort();
    void Clear();
    inline bool Exists(const T&) const;
    bool Empty() const {return this->size==0 ? true : false;};
    inline int Size() const {return this->size;};
    T* At(const int index);
    const T* At(int index) const; 
    friend ostream& operator << (ostream& out, const LinkedList<T>& that);
    T* operator[](const int);
    const T* operator[](const int) const;   
};
.
.
.

template <typename T>
ostream& operator << (ostream& out, const LinkedList<T>& that)
{
    if (!that.Empty())
        for(Node<T>* seeker=that.head; seeker; seeker=seeker->next)
            out<<seeker->info<<endl;
    return out;
}

По какой-то причине ошибка ссылки исчезает, когда я пишу вместо этого в объявлении функции друга вкласс:

template <typename T> friend ostream& operator << (ostream& out, const LinkedList<T>& that);

Ответы [ 2 ]

4 голосов
/ 17 декабря 2011

Дело в том, что объявленный вами друг не является шаблоном, поэтому данный экземпляр вашего << шаблона не тот, которого вы объявили другом.</p>

Если вы объявите друга таким, как этот

template <typename U> //or T, doesn't matter
friend ostream& operator << (ostream& out, const LinkedList<U>& that);

, тогда operator << <int> будет другом LinkedList<float>.Если это нежелательно, есть следующее решение:

friend ostream& operator <<<T> (ostream& out, const LinkedList<T>& that);

В этом случае только конкретный экземпляр шаблона является вашим другом, что может быть тем, что вам нужно.Эта статья подробно объясняет тему

2 голосов
/ 17 декабря 2011

Поскольку определение operator<< вне класса на самом деле шаблон функции, тогда как объявление друга внутри класса не является шаблоном функции.

Объявление friend являетсяне шаблонная функция, и ее аргументы фиксированы относительно шаблона класса.

Например, если вы создаете экземпляр шаблона класса с помощью int, friend становится следующим:

friend ostream& operator << (ostream& out, const LinkedList<int>& that);

, который сообщает компилятору, что "Я друг этого класса, я также не шаблонная функция, и вы найдете мое определение вне класса, точно с такой же сигнатурой.". Вы можете видеть, что аргументы исправлены.

Но когда вы делаете что-то вроде этого:

template <typename U>
friend ostream& operator << (ostream& out, const LinkedList<U>& that);

Это имеет смысл для компилятора, так как это согласуется с определением operator<<вне класса, который также является шаблоном функции.Но есть проблема: он делает каждую специализацию шаблона функции другом класса;означает, что когда U=float, operator<< может также получить доступ к закрытым членам LinkedList<int>, тогда как он должен иметь доступ только к закрытым членам LinkedList<float>.Итак, вы видите, что это проблема.

Лучшее решение было бы так: НЕ делайте его функциональным шаблоном и не определяйте друга внутри самого класса.

template<typename T>
class LinkedList
{
  public:


  friend ostream& operator << (ostream& out, const LinkedList<T>& that)
  {
      //definition 
  }
};
...