Queue with std::vector How can I improve this code?

template&lt;class T&gt;
class Queue {
public:
    Queue(const std::initializer_list&lt;T&gt;&amp; i) :elem{i} {}
    int size() const {
        return elem.size();
    }
    bool empty() const {
        return elem.empty();
    }
    void enqueue(T&amp;&amp;);
    void dequeue();
    T peek();
    T&amp; operator[](std::size_t);
    typename std::vector &lt;T&gt;::iterator begin() {
        return elem.begin();
    }
    typename std::vector &lt;T&gt;::iterator end() {
        return elem.end();
    }

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

template&lt;class T&gt;
void Queue&lt;T&gt;::enqueue(T&amp;&amp; t) {
    elem.push_back(t);
}

template&lt;class T&gt;
void Queue&lt;T&gt;::dequeue() {
    if (empty()) {
        throw std::out_of_range("underflow");
    }
    elem.erase(elem.begin());
}

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

template&lt;class T&gt;
T&amp; Queue&lt;T&gt;::operator[](std::size_t i) {
    if (empty() || i &lt; 0 || i &gt;= size()) {
        throw std::out_of_range("underflow");
    }
    return elem[i];
}
I assume that you are familiar with std::queue and std::deque and wrote this class as a reinventing-the-wheel exercise.

There are a few mainly aesthetic points that you could improve:


int size() is better if returning a std::size_t, which is the underlaying type returned by vector::size().
Keep parameter names in function prototypes, it helps self-documenting the code.
T peek() doesn't change any internal state, so it should be const too.
operator[] should be provided with two overloads, const and non-const:

T&amp; operator[](std::size_t index);
const T&amp; operator[](std::size_t index) const;


Otherwise you won't be able to access data in a const Queue&lt;T&gt;. The same thing applies to begin()/end(). You will have to provide both const and non-const versions. This is purely boilerplate code, but C++ doesn't offer a better solution.
This excessively long name: typename std::vector &lt;T&gt;::iterator should be replaced by a typedef or using alias:

using iterator = std::vector&lt;T&gt;::iterator;

// Then you simply use `iterator` now:
iterator begin() { ... }

Shouldn't you provide a constructor that takes no arguments? It is very likely that you will want to declare an empty queue at some point. A default constructor should also do:

Queue() = default;