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?
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.
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;
}
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()));
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 .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.