Generic Singly Linked List in C++
Design

It's relatively simple to create a double linked list!



Some things you should think about some more:


Please put your code into a namespace. Do you think that SinglyLinkedList is a very unique name in the global scope?
You need to look into const correctness.
You need to look into move semantics.




Major Bug.

You have not implemented the rule of three (or five). When a class contains an owned pointer the compiler generated copy constructor, copy assignment operator and destructor are not going to work correctly.

Your SinglyLinkedList contains the owned pointer: head. An owned pointer is one that you have taken responsibility for the lifespan of (and are thus going to call delete on it when it the object is destroyed.

{
     SinglyLinkedList&lt;int&gt;    list1;
     list1.addFirst(1);

     SinglyLinkedList&lt;int&gt;    list2(list1);
}
// This code is broken as you have a double delete.




Upgrade you need to do.

The standard library defines things called concepts. A concept is a set of properties that a class has. One of the big concepts of the standard is the concept of a "Container" (of which a singly linked list is). Ao you should probably make your list "Container" compliant.

Code Review

I hate useless comments.

    /** BEGIN NESTED NODE CLASS **/
    class Node {


That counts as a useless comment.



OK good start.

        Node(Node* n, const E&amp; d) : data(d), next(n) {}   ;
                 // Not Needed                           ^^^


But it does mean that you are required to copy the object into the list. Modern C++ has the concept of move semantics. So you should allow for moving the object into the list.

        Node(Node* n, E&amp;&amp; d) : data(std::move(d)), next(n) {}


Also you should allow the object to be constructed in place:

        template&lt;typename... Args&gt;
        Node(Node* n, Args&amp;&amp;... args)
            : data(std::forward&lt;Args&gt;(args)...)
            , next(n)
        {}




Here you get a reference to the object.
That's fine.

        E&amp; getData() { return data; }


But what happens if your list has been passed by const reference to a function. Now you can no longer accesses the data as you can't get a const reference to the data.

        E const&amp; getData() const {return data;}


Its a bit strange that you only return reference from the node. But you return only const references from the list?

    const E&amp; first() const;
    const E&amp; last() const;




I actually hate your get/set mentatility here. I see no need for it inside the node object itself.

        void setNext(Node* n) { next = n; }




That's fine.

    void print() const;


But two things to note.


There is more streams than the std::cout so allow this to be pramertized.
The normal way of streaming is via the output operator: operator&lt;&lt;()

void print(std::ostream&amp; stream = std::cout);
friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; str, SinglyLinkedList const&amp; data)
{
    data.print(str);
    return str;
}