STL queue implementation I've implemented a simple C++ STL like queue. (I've tried to follow @LokiAstari stack implementation code fashion)

#ifndef QUEUE_H
#define QUEUE_H

#include &lt;iostream&gt;
#include &lt;stdexcept&gt;

using std::cout;

template &lt;typename T&gt;
class queue {
public:
    struct node {
        T data;
        node *next;

        node()
            : data(0)
            , next(nullptr) {
        }

        node(T const&amp; data, node* next)
            : data(data)
            , next(next) {
        }

        node(T&amp;&amp; data, node* next)
            : data(std::move(data))
            , next(next) {
        }
    };
    ~queue();
    bool empty() const;
    size_t size() const;
    T front() const;
    void push(T const&amp; data);
    void push(T&amp;&amp; data);
    //void emplace (T&amp;&amp;... args);
    // void swap (queue&amp; x);
    void pop();

private:
    size_t elements = 0;
    node *head = nullptr;
    node *tail = nullptr;
};

template &lt;typename T&gt;
queue&lt;T&gt;::~queue() {
    node *curr = new node();
    while(head) {
        curr = head;
        head = head-&gt;next;
        delete curr;
    }
    delete tail;
}

template &lt;typename T&gt;
bool queue&lt;T&gt;::empty() const {
    return elements == 0;
//    return head == nullptr;
}

template &lt;typename T&gt;
size_t queue&lt;T&gt;::size() const {
    return elements;
}

template &lt;typename T&gt;
T queue&lt;T&gt;::front() const {
    if(elements == 0)
        throw std::runtime_error("Invalid Action");
    return head-&gt;data;
}

template &lt;typename T&gt;
void  queue&lt;T&gt;::push(T const&amp; data) {
    node *newNode = new node(data, nullptr);
    if(!elements) head = newNode;
    else tail-&gt;next = newNode;
    tail = newNode;
    ++elements;
}
template &lt;typename T&gt;
void  queue&lt;T&gt;::push(T&amp;&amp; data) {
    node *newNode = new node(std::move(data), nullptr);
    if(!elements) head = newNode;
    else tail-&gt;next = newNode;
    tail = newNode;
    ++elements;
}
template &lt;typename T&gt;
void  queue&lt;T&gt;::pop() {
    if(elements == 0)
        throw std::runtime_error("Invalid Action");
    node *tmp = new node();
    if(elements != 0) tmp = head;
    head = head-&gt;next;
    --elements;
    delete tmp;
}

#endif // QUEUE_H


I would appreciate all criticism relevant to code, style, flow, camelCase vs underscore, and so forth.
A few points that nearly jump out at me:


You've implemented it as a linked list of individually allocated nodes. This nearly guarantees poor locality of reference and for small types wastes quite a bit of space.
Your destructor leaks memory:

template &lt;typename T&gt;
queue&lt;T&gt;::~queue() {
    node *curr = new node();
    while(head) {
        curr = head;


This allocates a node (not clear why you'd want to allocate a node in the dtor, but there it is), then if head != nullptr, it overwrites that pointer with head, thus leaking the node it just allocated (and if that condition isn't met, it just flows off the end without doing any more with curr, also leaking the memory).
Your node type takes for granted that a T can be initialized from 0:

node()
    : data(0)


For a generic type, this assumption is unwarranted. You typically want to use T() to create a value-initialized object, which will be 0 for arithmetic types, a null pointer for a pointer type, an empty string for a string type, and so on.