EnDelt64
EnDelt64

Reputation: 1360

Redefinition of class as different kind of symbol

template <typename T>
class LinkedListNode {
public:
    friend class LinkedList;
    friend class LinkedListIterator;

    LinkedListNode(const T p_data) : data(p_data), next(nullptr) {}

    ~LinkedListNode() {
        std::cout << "~LinkedListNode()\n";
    }

private:
    T data;

    LinkedListNode<T>* next;
};

template <typename T>
class LinkedList { /* Redefinition of 'LinkedList' as different kind of symbol */
  ...
}

I made own linked-list data structure, but an error message is appeared to LinkedList class.

If I try to compile the code, another error is occured.

error: template argument required for ‘class LinkedList’
 class LinkedListNode {
                      ^


error: template placeholder type ‘LinkedListNode’ must be followed by a simple declarator-id
         LinkedListNode* pre_remove;
         ^~~~~~~~~~~~~~

I've added template <typename T> above LinkedList class so I can't understand why these error messages come out.

int main() {
    LinkedList li;
    ...
}

----------------------------------------------------
error: class template argument deduction failed:
     LinkedList li;
                ^~

Full source code of Linked List

Upvotes: 1

Views: 862

Answers (1)

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20141

As already hinted by dorKKnight, class LinkedList is actually a template. Hence, you have to use it as such – even in friend declarations.

template <typename T>
class LinkedListNode {
  friend class LinkedList<T>;

The other part of the story is that LinkedList and LinkedListNode have a circular dependency. To break this, a template forward declaration is needed.

// forward declaration
template <typename T>
class LinkedList;

A complete sample:

// forward declaration
template <typename T>
class LinkedList;

template <typename T>
class LinkedListNode {
  friend class LinkedList<T>;
  public:
    const T value;
  private:
    LinkedListNode *pNext;
  public:
    LinkedListNode(const T value): value(value), pNext(nullptr) { }
    ~LinkedListNode() = default;

};

template <typename T>
class LinkedList {
  LinkedListNode<T> *pFirst, *pLast;

  public:
    LinkedList(): pFirst(nullptr), pLast(nullptr) { }

    void push(const T value)
    {
      if (!pFirst) pFirst = pLast = new LinkedListNode<T>(value);
      else {
        pLast->pNext = new LinkedListNode<T>(value);
        pLast = pLast->pNext;
      }
    }
    void print(const char *sep = " ")
    {
      std::cout << "{";
      for (LinkedListNode<T> *pNode = pFirst; pNode; pNode = pNode->pNext) {
        std::cout << sep << pNode->value;
      }
      std::cout << sep << "}";
    }
};

int main()
{
  LinkedList<int> list;
  list.push(1); list.push(2); list.push(3);
  list.print();
}

Output:

{ 1 2 3 }

Live Demo on coliru


A matter of design:

It is usual to embed the class for a single node into the template class for the list because the node class is a list detail which need not to be “seen” anywhere else.

Redesigning the above sample:

#include <iostream>

template <typename T>
class LinkedList {

  private:
    struct Node {
      const T value;
      Node *pNext;

      Node(const T value): value(value), pNext(nullptr) { }

    };

    Node *pFirst, *pLast;

  public:
    LinkedList(): pFirst(nullptr), pLast(nullptr) { }

    void push(const T value)
    {
      if (!pFirst) pFirst = pLast = new Node(value);
      else {
        pLast->pNext = new Node(value);
        pLast = pLast->pNext;
      }
    }
    void print(const char *sep = " ")
    {
      std::cout << "{";
      for (Node *pNode = pFirst; pNode; pNode = pNode->pNext) {
        std::cout << sep << pNode->value;
      }
      std::cout << sep << "}";
    }
};

int main()
{
  LinkedList<int> list;
  list.push(1); list.push(2); list.push(3);
  list.print();
}

Output:

{ 1 2 3 }

Live Demo on coliru

As a bonus, the forward issue has been vanished.

Upvotes: 1

Related Questions