Ошибка компилятора при объявлении класса друга шаблона в классе шаблона

Я пытался реализовать свой собственный класс связанного списка в дидактических целях.

Я указал класс «List» в качестве друга в объявлении Iterator, но, похоже, он не компилируется.

Это интерфейсы трех классов, которые я использовал:

Node.h:

#define null (Node<T> *) 0

template <class T>
class Node {
 public:
    T content;
    Node<T>* next;
    Node<T>* prev;

    Node (const T& _content) :
        content(_content),
        next(null),
        prev(null)
    {}
};

Iterator.h:

#include "Node.h"

template <class T>
class Iterator {
 private:
    Node<T>* current;

    Iterator (Node<T> *);

 public:
    bool isDone () const;

    bool hasNext () const;
    bool hasPrevious () const;
    void stepForward ();
    void stepBackwards ();

    T& currentElement () const;

    friend class List<T>;
};

List.h

#include <stdexcept>
#include "Iterator.h"

template <class T>
class List {
 private:
    Node<T>* head;
    Node<T>* tail;
    unsigned int items;

 public:
    List ();

    List (const List<T>&);
    List& operator = (const List<T>&);

    ~List ();

    bool isEmpty () const {
        return items == 0;
    }
    unsigned int length () const {
        return items;
    } 
    void clear ();

    void add (const T&);
    T remove (const T&) throw (std::length_error&, std::invalid_argument&);

    Iterator<T> createStartIterator () const throw (std::length_error&);
    Iterator<T> createEndIterator () const throw (std::length_error&);
};

И это тестовая программа, которую я пытался запустить:

trial.cpp

using namespace std;
#include <iostream>
#include "List/List.cc"

int main ()
{
 List<int> myList;

 for (int i = 1; i <= 10; i++) {
  myList.add(i);
 }

 for (Iterator<int> it = myList.createStartIterator(); !it.isDone(); it.stepForward()) {
  cout << it.currentElement() << endl;
 }

 return 0;
}

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

Iterator.h: 26: ошибка: «Список» не является шаблоном

Iterator.h: в экземпляре ‘Iterator’:

trial.cpp: 18: создан отсюда

Iterator.h: 12: error: аргумент шаблона необходим для "struct List"

List.cc: в функции-члене ‘Iterator List :: createStartIterator () const [with T = int]’:

trial.cpp: 18: создан отсюда

Iterator.h: 14: error: ‘Iterator :: Iterator (Node *) [with T = int]’ является частным

List.cc:120: ошибка: в этом контексте

Похоже, он не распознает объявление о дружбе. Где я ошибся?


person Davide Valdo    schedule 03.01.2010    source источник
comment
Не определяйте свой собственный макрос NULL (или NULL или что-либо подобное). В случае инициализации элементов данных 0 работает нормально.   -  person    schedule 03.01.2010
comment
Я знаю, что это некрасиво, это было временно. Но я был совершенно уверен, что C ++ не допускает неявное приведение типов.   -  person Davide Valdo    schedule 03.01.2010
comment
Приведения никогда не бывают неявными, но преобразования есть. (Можно сказать, две стороны одной медали, и преобразование также используется для именования методов, которые преобразуют значение среди других применений, но это другой тип преобразования.) Для инициализации указателя вам понадобится еще один указатель подходящего типа. , или константа нулевого указателя; 0 - прекрасная константа нулевого указателя (NULL тоже, если хотите).   -  person    schedule 03.01.2010
comment
Вам также необходимо будет определить методы вашего шаблона класса (List) в заголовке (вместо List.cc, который не должен # включаться в хороший код) в общем случае, потому что шаблоны классов и шаблоны функций на самом деле не классы и функции, они генерируют классы и функции, и полный код должен быть доступен компилятору.   -  person    schedule 03.01.2010


Ответы (2)


попробуйте добавить предварительную декларацию

template <class T> class List;

в начале Iterator.h - это может быть то, что вам нужно, чтобы объявление friend внутри класса Iterator работало.

person Alex Martelli    schedule 03.01.2010

Проблема в том, что List не был должным образом объявлен в Iterator.h. Вместо этого вложите класс Iterator в List (автоматически сделав его шаблоном), что вы, вероятно, захотите сделать в любом случае (чтобы использовать List :: Iterator вместо переименования его в ListIterator или IteratorForList, так как у вас будет более одного Iterator в пространстве имен).

template<class T>
struct List {
  //...
  struct Node {/*...*/};
  struct Iterator {
    // ...
  private:
    Iterator(Node*);
    friend class List; // still required
  };
  //...
};
person Community    schedule 03.01.2010