Paste in an STL queue using std :: copy

I would like to use std::copy to insert elements into the queue as follows:

 vector<int> v; v.push_back( 1 ); v.push_back( 2 ); queue<int> q; copy( v.begin(), v.end(), insert_iterator< queue<int> >( q, q.front() ) ); 

But this does not compile, complaining that begin not a member of std::queue .

Note: I also tried this with std::inserter - this also failed, this time I said that 'reference' is not a member of 'std :: queue'. std::back_inserter and std::back_insert_iterator also std::back_insert_iterator with the same error.

Am I missing something or is insert_iterator just not working with queues?

+16
c ++ queue stl copy
Nov 12 '09 at 16:28
source share
9 answers

Unfortunately, std::queue "adapts" a function known as push_back to just push , which means that the standard back_insert_iterator does not work.

Probably the easiest way (albeit conceptually ugly) is to adapt the container adapter with the adapter adapter short-circuit [sic] (eugh!), Which is as long as the back insert iterator is used.

 template<class T> class QueueAdapter { public: QueueAdapter(std::queue<T>& q) : _q(q) {} void push_back(const T& t) { _q.push(t); } private: std::queue<T>& _q; }; 

Used as follows:

 std::queue<int> qi; QueueAdapter< std::queue<int> > qiqa( qi ); std::copy( v.begin(), v.end(), std::back_inserter( qiqa ) ); 
+21
Nov 12 '09 at 16:58
source share

The queue does not allow iteration through its elements.

From SGI STL Docs :

A queue is an adapter that provides a limited subset of the container. Functionality A queue is the first in (FIFO). 1 That is, items are added to the back of the queue and can be removed from the front; Q.front () is an item added to the queue in Recently, the queue does not allow iteration through its elements. [2]

You can do this work, but you cannot use insert_iterator . You need to write something like queue_inserter that represents the iterator interface.

Update . I could not help myself and try to implement the iterator that you need. Here are the results:

 template< typename T, typename U > class queue_inserter { queue<T, U> &qu; public: queue_inserter(queue<T,U> &q) : qu(q) { } queue_inserter<T,U> operator ++ (int) { return *this; } queue_inserter<T,U> operator * () { return *this; } void operator = (const T &val) { qu.push(val); } }; template< typename T, typename U > queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) { return queue_inserter<T,U>(q); } 

This works great for features like this:

 template<typename II, typename OI> void mycopy(II b, II e, OI oi) { while (b != e) { *oi++ = *b++; } } 

But this does not work with a copy of STL, because STL is stupid.

+8
Nov 12 '09 at 16:38
source share

std::queue not a container in the sense of STL, it is a container adapter with very limited functions. For what you think you need, either std::vector or std::deque (the "double queue", which is the "real container"), seems to be the right choice.

+3
Nov 12 '09 at 16:34
source share

I'm sure this just won't work - the queue provides push , but the insert iterator expects to use push_front or push_back . There is no real reason why you could not write your own push_insert_iterator (or any other name you prefer), but that is a bit of a pain ...

+3
Nov 12 '09 at 16:43
source share

insert_iterator and back_insert_iterator work only with containers (or adapters) with (respectively) insert and push_back methods - queue . You can write your own iterator modeled on them, something like this:

 template <typename Container> class push_iterator : public iterator<output_iterator_tag,void,void,void,void> { public: explicit push_iterator(Container &c) : container(c) {} push_iterator &operator*() {return *this;} push_iterator &operator++() {return *this;} push_iterator &operator++(int) {return *this;} push_iterator &operator=(typename Container::const_reference value) { container.push(value); return *this; } private: Container &container; }; 

If this does not already exist, but I am sure that it does not.

+3
Nov 12 '09 at 16:55
source share

You will need a push_inserter (i.e. an insert that executes push es in a queue). As far as I know, there is no such iterator in STL. What I usually do is sadly returning to the good old loop.

If you have the courage, you can flip your own iterator, something like this:

 template <typename Container> class push_insert_iterator { public: typedef Container container_type; typedef typename Container::value_type value_type; explicit push_insert_iterator(container_type & c) : container(c) {} // construct with container push_insert_iterator<container_type> & operator=(const value_type & v) { //push value into the queue container.push(v); return (*this); } push_insert_iterator<container_type> & operator*() { return (*this); } push_insert_iterator<container_type> & operator++() { // Do nothing return (*this); } push_insert_iterator<container_type> operator++(int) { // Do nothing return (*this); } protected: container_type & container; // reference to container }; template <typename Container> inline push_insert_iterator<Container> push_inserter(Container & c) { return push_insert_iterator<Container>(c); } 

This is just a draft, but you have an idea. It works with any container (or, say, container adapters) using the push method (for example, queue , stack ).

+2
Nov 12 '09 at 16:40
source share

std::queue not one of the main containers in the STL. This is a container adapter that is built using one of the basic STL containers (in this case, one of the serial containers: std::vector std::deque or std::list ). It is designed specifically for FIFO behavior and does not provide random insertion on the given iterator that you want insert_iterator to work. Therefore, it will be impossible to use such a queue.

The easiest way I could come up with is:

 class PushFunctor { public: PushFunctor(std::queue<int>& q) : myQ(q) { } void operator()(int n) { myQ.push(n); } private: std::queue<int>& myQ; }; 

And use it like:

 queue<int> q; PushFunctor p(q); std::for_each(v.begin(), v.end(), p); 
+1
Nov 12 '09 at 16:41
source share

In this simple case, you can write:

 vector<int> v; v.push_back( 1 ); v.push_back( 2 ); queue<int, vector<int> > q(v); 

This will make a copy of vector and use it as the base queue container.

Of course, this approach will not work if you need to insert objects after creating the queue.

0
Nov 12 '09 at 16:48
source share

for c ++ 11

 std::for_each( v.begin(), v.end(), [&q1](int data) { q1.push(data); } ); 

and c ++ 14

 std::for_each( v.begin(), v.end(), [&q1](auto data) { q1.push(data); } ); 
0
Sep 05 '19 at 16:33
source share



All Articles