Separate Declaration and Definition of private Node implementation in template Linked List I was practicing implementing a template Linked List with a private node implementation.  I know one of the methods to define template class member functions is to keep the declaration and definition in the same header file.  When I tried to do this with the private createNode() function, I could not get it to work.

template&lt;class T&gt;
LinkedList&lt;T&gt;::createNode(const T &amp;data)
{ ... }


I was wondering if there's a way to define the private function createNode() outside of the class declaration?  My current work around is to define this function within the class definition.  As I understand, this is a C++ style no-no though.

Generally speaking, I was wondering if there was anything else I could do with my implementation that could improve readability or make the  code more robust.  I'm open to any and all suggestions!  I suppose the first suggestion is to be consistent with where I place the pointer/reference modifiers...

#include &lt;iostream&gt;

template&lt;class T&gt;
class LinkedList
{
private:
    struct Node
    {
        T data;
        Node* next;
    };

    Node* head;
    Node* tail;
    int size;

    Node* createNode(const T &amp;data)
    {
        Node* newNode = new Node;
        newNode-&gt;data = data;
        newNode-&gt;next = nullptr;

        return newNode;
    }

public:
    LinkedList();
    void display() const;
    void push(const T &amp;data);
    void insert(const int pos, const T &amp;data);
    void remove(const int pos);

};

template&lt;class T&gt;
LinkedList&lt;T&gt;::LinkedList() : head{ nullptr }, tail{ nullptr }, size{ 0 }
{
}

template&lt;class T&gt;
void LinkedList&lt;T&gt;::display() const
{
    Node* curNode = head;

    while (curNode != nullptr)
    {
        std::cout &lt;&lt; curNode-&gt;data &lt;&lt; std::endl;
        curNode = curNode-&gt;next;
    }

    std::cout &lt;&lt; std::endl;
}

template&lt;class T&gt;
void LinkedList&lt;T&gt;::push(const T &amp;data)
{
    Node* newNode = createNode(data);

    if (size == 0)
    {
        head = newNode;
        tail = newNode;
    }
    else 
    {
        tail-&gt;next = newNode;
        tail = newNode;
    }

    ++size;
}

template&lt;class T&gt;
void LinkedList&lt;T&gt;::insert(const int pos, const T &amp;data)
{
    if (pos &lt; 0 || pos &gt; size)
    {
        std::cout &lt;&lt; "Index is out of range!" &lt;&lt; std::endl;   
    }
    else if (pos == size)
    {
        push(data);   
    }
    else
    {
        Node* newNode = createNode(data);
        Node* prevNode = head;
        Node* curNode = head;

        int i = 0;
        while (i != pos)
        {
            prevNode = curNode;
            curNode = curNode-&gt;next;
            ++i;
        }

        prevNode-&gt;next = newNode;
        newNode-&gt;next = curNode;

        ++size;
    }
}

template&lt;class T&gt;
void LinkedList&lt;T&gt;::remove(const int pos)
{
    if (pos &lt; 0 || pos &gt; size)
    {
        std::cout &lt;&lt; "Index is out of range!" &lt;&lt; std::endl;   
    }
    else if (size == 0)
    {
        std::cout &lt;&lt; "List is empty!" &lt;&lt; std::endl;   
    }
    else
    {
        Node* prevNode = head;
        Node* curNode = head;

        int i = 1;
        while (i != pos)
        {
            prevNode = curNode;
            curNode = curNode-&gt;next;
            ++i;
        }

        prevNode-&gt;next = curNode-&gt;next;
        delete curNode;

        if (pos == size)
        {
            tail = prevNode;   
        }

        --size;
    }
}
Your LinkedList does not manage its resources. You need a dtor, user-defined copy-ctor and user-defined assignment-operator at least.
Don't interact with the user from generic library code. Report any errors to the caller instead!
You probably want to provide the lists size to the public. Otherwise, consider whether optimizing removal of non-existent elements and insertion at the end by index is worth the overhead.
Only use std::endl if you really have to flush the stream. Remember flushing kills performance.
All your while-loops would be better off as for-loops.
createNode leaks memory if assignment to .data fails. Anyway, use aggregate-initialization, and you'll see that it's just not worth separating out into its own function:

auto p = new Node{data};



Regarding defining things in-class: There's nothing wrong with that, it's often even preferable, especially for templates.
If you define something outside a class in a header though, remember it won't automatically marked inline, meaning it must not be included in more than one compilation-unit.