user3478252
user3478252

Reputation: 17

Passing template parameters to nested structs

I'm trying to add a nested struct (Node) that takes the same template param 'T' passed into the baseclass (LinkedList).

When I try to template the outer LinkedList class, I get a "explicit specialization of non-template class LinkedList" error. If I don't add it, the private Nodes "head" and "tail" don't recognize 'T'

When I add the template to the Node class, I get a "Declaration of 'T' shadows template parameter" error. However, if I don't add it explicitly to the Node class, the 'T' is not recognized at all in the struct.

How do I declare template and pass it correctly from the LinkedList class to the nested, private Node struct correctly?

template<class T>
class LinkedList<T> {

private:
    template<typename T>
    struct Node {
        T value;
        Node<T>* next;
        Node<T>* previous;
        Node<T>(T value, Node<T>* next, Node<T>* previous)
        :value(value),
        next(next),
        previous(previous){}
        Node<T>& operator=(const Node<T>&) = delete;
    };

    Node<T>* head;
    Node<T>* tail;

    LinkedList& operator=(const LinkedList&) = delete;

public:
    LinkedList<T>()
        :head(nullptr),
        tail(nullptr){}
    ~LinkedList<T>();
    LinkedList& insertTail(T value);

};

Upvotes: 1

Views: 855

Answers (2)

WhozCraig
WhozCraig

Reputation: 66194

Lose all the extraneous <T> madness and simply used the outer template parameter. It is perfectly legal to do so:

template<class T>
class LinkedList
{
private:
    struct Node {
        T value;
        Node* next;
        Node* previous;

        Node(T value, Node* next, Node* previous)
            : value(value), next(next), previous(previous)
        {}
        Node& operator=(const Node&) = delete;
    };

    Node* head;
    Node* tail;

    LinkedList& operator=(const LinkedList&) = delete;

public:
    LinkedList()
        : head(nullptr)
        , tail(nullptr)
    {}
    ~LinkedList();

    LinkedList& insertTail(T value);
};

Related: My crystal ball tells me you should read this before implementing the rest of the functions that are only declared here.

Best of luck.

Upvotes: 3

T.C.
T.C.

Reputation: 137310

When declaring a primary template (i.e., not a specialization), don't add <T> after the name:

template<class T>
class LinkedList {

Node shouldn't be a template; for any particular T, a LinkedList<T> should only have one type of Nodes - those that hold T:

struct Node {
    T value;
    Node* next;
    // ...
};

Finally, the <T> is implied when you write the template's name in its definition, so you don't need to explicitly specify it:

LinkedList() 
    :head(nullptr),
    tail(nullptr){}
~LinkedList();

Upvotes: 2

Related Questions