GCC compiler error when dealing with template classes 'error:invalid use of incomplete type template'

GCC compiler error when dealing with template classes 'error:invalid use of incomplete type template'

为了防止模板class的特殊化错误,我已经将某些class的声明和实现放在了list.h文件中:

#ifndef _LIST_
#define _LIST_

#include <iostream>
#include <cstddef>

#define push() append();
#define pop() remove();
#define _DEBUG 1

template <class T>
class ListNode //Employee class
{
public:
#if _DEBUG
    unsigned int index = 0; //Test only.
#endif
    T data; //Can be replaced by any other types.
    ListNode<T> *prev = NULL;
    ListNode<T> *next = NULL;

public:
    ListNode(int userInputData) : data(userInputData), prev(NULL), next(NULL){};
    ListNode() : prev(NULL), next(NULL){};
};

template <class T>
using node = ListNode<T>;

template <class T>
class SINGLY_LINKED_LIST //Manager class
{
private:
    ListNode<T> *head = NULL;
    ListNode<T> *tail = NULL;
    unsigned int len = 0;

public:
    SINGLY_LINKED_LIST() : head(NULL), tail(NULL), len(0){};          //Void construct function.
    SINGLY_LINKED_LIST(ListNode<T> *start_node, int userInputlength); //Init by a node and length.

    bool print(void); //Print a list on screen.

    int get_length(void);                    //Get the length of the whole list.
    int get_length(ListNode<T> *start_node); //Get the length of a sub-list.(start from start_ndoe)

    ListNode<T> *operator[](unsigned int N); //Access to the address(ptr) of node.
    ListNode<T> *begin(void);                //Return the head pointer of list.
    ListNode<T> *end(void);                  //Return the tail pointer of list.

    bool remove(void);                                                    //Remove last node->pop().
    bool remove(ListNode<T> *start_node);                                 //Remove a chosen node.
    bool remove(int N);                                                   //Remove a node that 'N' blocks from the head_node.
    bool remove(ListNode<T> *start_node, int N);                          //Remove a node that 'N' blocks from the start_node(reference argument).
    int remove(bool (*cmp)(int stock_val, int input_val), int input_val); //Remove node match the value,return num.

    bool destroy(void);                                           //Destroy the whole list.
    bool destroy(ListNode<T> *start_node, ListNode<T> *end_node); //Destroy a part of the list.(destroy a sub-list by start_node to end_node)

    ListNode<T> *push_back(void);                  //Add back a new node<T>.
    ListNode<T> *push_back(unsigned int num);      //Add back a dozen of nodes.
    ListNode<T> *push_back(ListNode<T> *add_node); //Add back a selected node(pointer).

    ListNode<T> *push_front(unsigned int num); //Add several node at front.
    ListNode<T> *push_front(void);             //Add a node at front.

    ListNode<T> *insert(ListNode<T> *position);                           //Insert one node(by default)at position.
    ListNode<T> *insert(ListNode<T> *position, unsigned int num);         //Insert several node at posotion.
    ListNode<T> *insert(ListNode<T> *position, ListNode<T> *chosen_node); //Insert a chosen node at position.

    ListNode<T> *find(bool (*cmp)(int stock_val, int input_val), int input_val); //Find the first element equal to 'input_val'.
};

template <class T>
using SLL = SINGLY_LINKED_LIST<T>;

template <class T>
SLL<T>::SINGLY_LINKED_LIST(ListNode<T> *start_node, int userInputlength) : len(userInputlength)
{
    if (start_node->next == NULL && userInputlength >= 2)
    {
        this->head = start_node; //Save the head one address.
        ListNode<T> *p = head;
        for (int i = 1; i < userInputlength; i++)
        {
            p->next = new ListNode<T>;
            p = p->next;

            p->index = i;
            p->data = i; //for test only.

            p->next = NULL;
        }
        this->tail = p; //Save the last one address.
    }
    else
    {
        if (start_node->next == NULL)
        {
            std::cout << "[Error] List short or equal to '1'" << '\n';
        }
        else
        {
            std::cout << "[Error] This node has been in a list already!" << '\n';
        }
    }
}

template <class T>
ListNode<T> *SLL<T>::operator[](unsigned int N)
{
    if (N < this->len)
    {
        ListNode<T> *p = this->head;
        for (int i = 0; i < N; i++)
        {
            p = p->next;
        }
        return p;
    }
    else
    {
        std::cout << "[Error] Size overflow!" << '\n';
        return NULL;
    }
}

以及 class SLL 的其他成员函数如下...

gcc 编译器然后说:

In file included from main.cpp:2:
list.h:78:72: error: invalid use of incomplete type 'class SINGLY_LINKED_LIST<T>'
 SLL<T>::SINGLY_LINKED_LIST(ListNode<T> *start_node, int userInputlength) : len(userInputlength)
                                                                        ^
In file included from main.cpp:2:
list.h:31:7: note: declaration of 'class SINGLY_LINKED_LIST<T>'
 class SINGLY_LINKED_LIST //Manager class
       ^~~~~~~~~~~~~~~~~~
In file included from main.cpp:2:
list.h:110:47: error: invalid use of incomplete type 'class SINGLY_LINKED_LIST<T>'
 ListNode<T> *SLL<T>::operator[](unsigned int N)
                                               ^
In file included from main.cpp:2:
list.h:31:7: note: declaration of 'class SINGLY_LINKED_LIST<T>'
 class SINGLY_LINKED_LIST //Manager class

g++ 似乎对这个别名有问题(而 clang++MSVC 接受它):

template <class T>
using SLL = SINGLY_LINKED_LIST<T>;

所以,放弃它并使用 SINGLY_LINKED_LIST<T> 代替:

template <class T>
SINGLY_LINKED_LIST<T>::SINGLY_LINKED_LIST(ListNode<T> *start_node, int userInputlength)

template <class T>
ListNode<T> *SINGLY_LINKED_LIST<T>::operator[](unsigned int N)