Extremely simple stack implementation using a vector Please review my simple Stack:

template&lt;class T&gt;
class Stack {
public:
    Stack() = default;
    Stack(std::initializer_list&lt;T&gt; i) :n{} {
        for (auto&amp; x : i) {
            elem.push_back(x);
            ++n;
        }
    }
    Stack(const Stack&lt;T&gt;&amp;) = default;
    Stack(Stack&lt;T&gt;&amp;&amp;) = default;
    Stack&amp; operator=(const Stack&amp;) = default;
    Stack&amp; operator=(Stack&amp;&amp;) = default;
    ~Stack() = default;
    int size() const {
        return n;
    }
    bool isEmpty() const {
        return (n == 0);
    }
    void push(T);
    T pop();
    T&amp; peek();

private:
    std::vector&lt;T&gt; elem;
    int n;
};

template&lt;class T&gt;
void Stack&lt;T&gt;::push(T t) {
    elem.push_back(t);
    ++n;
}

template&lt;class T&gt;
T Stack&lt;T&gt;::pop() {
    if (isEmpty()) {
        throw std::out_of_range("underflow");
    }
    T t = *elem.erase(elem.end()-1);
    --n;
    return t;
}

template&lt;class T&gt;
T&amp; Stack&lt;T&gt;::peek() {
    if (isEmpty()) {
        throw std::out_of_range("underflow");
    }
    return elem[n-1];
}


How can I make this code better and build more complicated data structures based on stacks?
Remove int n;from member variable.
Underlying container std::vector holds the size information of the stack class. It increases the size of stack class object by sizeof(int). 

Remove various default definition methods from your class. Compiler would generate it for such classes. Due to these definition your class looks more verbose.

Implement all your member functions using the underlying container classes.

Prefer the standard name of your method instead of other. This way any program would easily use your custom class instead of std::stack. Change the isEmpty() to empty()

Your implementation can be simplified as below. 

template&lt;class T&gt;
class Stack {
public:
    Stack(const std::initializer_list&lt;T&gt;&amp; i):elem(i) {}
    int size() const { return elem.size(); }
    bool empty() const { return elem.empty();}
    void push(const T&amp;);
    T pop();
    T peek();
private:
    std::vector&lt;T&gt; elem;
};


template&lt;class T&gt;
void Stack&lt;T&gt;::push(const T&amp; t) {
    elem.push_back(t);
}

template&lt;class T&gt;
T Stack&lt;T&gt;::pop() {
    if (empty()) {
        throw std::out_of_range("underflow");
    }
    auto x = elem.back();  
    elem.pop_back();
    return x;
}

template&lt;class T&gt;
T Stack&lt;T&gt;::peek() {
    if (empty()) {
        throw std::out_of_range("underflow");
    }
    return elem.back();
}