20

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?

CinCout
  • 9,486
  • 12
  • 49
  • 67
Anthony
  • 443
  • 1
  • 5
  • 16

4 Answers4

22

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.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • I think I could do it. Derive from queue in a hack. The hack constructs from a queue, but instead of taking the data it creates a vector from the c. Then it has an operator vector. Then hide the hack in a helper function. The source queue remains mutated. – Yakk - Adam Nevraumont Aug 01 '16 at 13:27
  • @Yakk true, but there is no way to do this without suffering either an extra copy of the container or a mutation (move-from) – Richard Hodges Aug 01 '16 at 14:27
  • The same is true of `deque` tho, which your last sentence doesn't imply. – Yakk - Adam Nevraumont Aug 01 '16 at 19:43
10

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()));
CinCout
  • 9,486
  • 12
  • 49
  • 67
  • 4
    you probably want to **move** the objects returned from `q.front()` rather than copy them: `v.emplace_back(std::move(q.front()));`. non the less, you got my upvote because this is the only answer which actually practical – David Haim Aug 01 '16 at 13:01
7

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;
}
Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • 1
    @Max You could also inherit privately or compose, but then you would have to expose all the underlying interface (e.g., with `using`). It depends on the context. – Ami Tavory Sep 13 '18 at 22:08
  • Thank you. I understood. – Max Sep 13 '18 at 22:17
3

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.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    FWIW it is defined as `Container c;` in the standard so I would assume all conforming implementations use `c`. – NathanOliver Aug 01 '16 at 13:06
  • 4
    Vector based queues would be horribly slow. – Yakk - Adam Nevraumont Aug 01 '16 at 13:25
  • could you provide some more detail on what actually is happening in the `return->c` part ? not really sure I understand it – serup Jan 19 '17 at 13:37
  • @serup `my_queue` makes `std::vector` as the underlying container. The variable inside `std::queue` which holds this container is named as `c`. It must be true for all conforming compilers. Now within the `std::queue` since you have the `std::vector` readily available in form of `protected: c`, we don't have to convert this `std::queue` to `std::vector` explicitly using loop iteration. Rather we can simply pass on the `c` when needed. It has to be `this->c` because `c` belongs to base class with dependent type. – iammilind Jan 19 '17 at 14:45
  • and dependent type means that the this pointer takes type of base class which is T ? – serup Jan 20 '17 at 06:49