Reputation: 483
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
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
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.
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
.
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!!
my_queue<int> q;
q.push(1);
q.push(2);
std::vector<int>& v = q.to_vector();
Demo.
Upvotes: 3
Reputation: 69854
The correct container to model both queue_like behaviour and vector-like behaviour is a std::deque
.
This has the advantages of:
constant-time insertion and deletion at either end of the deque
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
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