Anthony
Anthony

Reputation: 483

How to convert std::queue to std::vector

I need to make use of a queue of doubles because of the good properties it has as an ordered container. I want to pass this queue to a class constructor that accepts vectors. If I do that directly I get the following error:

candidate constructor not viable: no known conversion from 'std::queue' to 'std::vector &' for 2nd argument

How to cast a queue to a vector?

Upvotes: 23

Views: 44337

Answers (4)

CinCout
CinCout

Reputation: 9619

I don't think there's any direct way available. Hence this can be achieved by adding elements one by one to the vector.

std::vector<int> v;
while (!q.empty())
{
    v.push_back(q.front());
    q.pop();
}

Note that the queue will be empty after this.

As suggested by @David in the comment, it'd be good to avoid copying the queue elements (helpful especially when the contained objects are big). Use emplace_back() with std::move() to achieve the same:

v.emplace_back(std::move(q.front()));

Upvotes: 12

iammilind
iammilind

Reputation: 69988

This is just an approach to avoid copying from std::queue to std::vector. I leave it up to you, if to use it or not.

Premises

std::queue is a container adaptor. The internal container by default is std::deque, however you can set it to std::vector as well. The member variable which holds this container is marked as protected luckily. Hence you can hack it by subclassing the queue.

Solution (!)

template<typename T>
struct my_queue : std::queue<T, std::vector<T>>
{
  using std::queue<T, std::vector<T>>::queue;
  // in G++, the variable name is `c`, but it may or may not differ
  std::vector<T>& to_vector () { return this->c; }
};

That's it!!

Usage

my_queue<int> q;
q.push(1);
q.push(2);
std::vector<int>& v = q.to_vector();

Demo.

Upvotes: 3

Richard Hodges
Richard Hodges

Reputation: 69854

The correct container to model both queue_like behaviour and vector-like behaviour is a std::deque.

This has the advantages of:

  1. constant-time insertion and deletion at either end of the deque

  2. ability to iterate elements without destroying the deque

std::deque supports the begin() and end() methods which means you can construct a vector (with compatible value-type) directly.

#include <vector>
#include <deque>

class AcceptsVectors
{
public:
  AcceptsVectors(std::vector<double> arg);
};

int main()
{
    std::deque<double> myqueue;

    auto av = AcceptsVectors({myqueue.begin(), myqueue.end()});
}

A non-mutating conversion of a queue to a vector is not possible.

Upvotes: 23

Ami Tavory
Ami Tavory

Reputation: 76297

std::vector has a constructor taking a pair of iterators, so if you would be able to iterate over the queue, you would be set.

Borrowing from an answer to this question, you can indeed do this by subclassing std::queue:

template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
    typedef typename Container::const_iterator const_iterator;

    const_iterator begin() const { return this->c.begin(); }                                                                               
    const_iterator end() const { return this->c.end(); }
};

(Note we're allowing only const iteration; for the purpose in the question, we don't need iterators allowing modifying elements.)

With this, it's easy to construct a vector:

#include <queue>
#include <vector>

using namespace std;

template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
    typedef typename Container::const_iterator const_iterator;

    const_iterator begin() const { return this->c.begin(); }                                                                               
    const_iterator end() const { return this->c.end(); }
};

int main() {
    iterable_queue<int> int_queue;
    for(int i=0; i<10; ++i)
        int_queue.push(i);

    vector<int> v(int_queue.begin(), int_queue.end());
    return 0;
}

Upvotes: 8

Related Questions