Подтвердить что ты не робот

Вставка в очередь STL с использованием std:: copy

Я хотел бы использовать std::copy для вставки элементов в очередь следующим образом:

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() ) );

Но это не компилируется, жалуясь, что begin не является членом std::queue.

Примечание: я тоже попробовал это с std::inserter - это тоже не удалось, на этот раз я сказал, что 'reference' не является членом 'std::queue'. std::back_inserter и std::back_insert_iterator также завершаются с той же ошибкой.

Я что-то упускаю из виду, или insert_iterator просто не работает с очередями?

4b9b3361

Ответ 1

К сожалению, std::queue "адаптирует" функцию, известную как push_back, к просто push, что означает, что стандартный back_insert_iterator не работает.

Вероятно, самым простым способом (хотя и концептуально уродливым) является адаптация адаптера контейнера с адаптером адаптера адаптера с коротким замыканием [sic] (eugh!), который до тех пор, пока используется итератор задней вставки.

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;
};

Используется следующим образом:

std::queue<int> qi;

QueueAdapter< std::queue<int> > qiqa( qi );

std::copy( v.begin(), v.end(), std::back_inserter( qiqa ) );

Ответ 2

Очередь не позволяет итерации через свои элементы.

Из SGI STL Docs:

Очередь - это адаптер, который обеспечивает ограниченное подмножество контейнера Функциональность Очередь - это "первая в (FIFO). 1То есть, элементы добавляются к назад очереди и может быть удален с фронта; Q.front() - это элемент, добавленный в очередь в последнее время. Очередь не позволяет итерации через его элементы. [2]

Вы можете выполнить эту работу, но вы не можете использовать insert_iterator. Вам нужно написать что-то вроде queue_inserter, которое представляет интерфейс итератора.

Обновление. Я не мог с собой поделать и попытаться реализовать итератор, в котором вы нуждаетесь. Вот результаты:

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);
}    

Это отлично работает для таких функций:

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

Но это не работает с копией STL, потому что STL глуп.

Ответ 3

std::queue не является контейнером в смысле STL, это контейнерный адаптер с очень ограниченными функциями. Для того, что вам кажется, вам нужно либо std::vector, либо std::deque ( "двойная очередь", которая является "реальным контейнером" ), кажется правильным выбором.

Ответ 4

Я уверен, что это просто не сработает - очередь предоставляет push, но итератор вставки ожидает использовать push_front или push_back. Нет никакой реальной причины, по которой вы не могли бы написать свой собственный push_insert_iterator (или любое другое имя, которое вы предпочитаете), но это немного боль...

Ответ 5

insert_iterator и back_insert_iterator работают только с контейнерами (или адаптерами) с (соответственно) insert и push_back методами - queue. Вы можете написать свой собственный итератор, смоделированный на них, примерно так:

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;
};

Если такое уже не существует, но я уверен, что этого не делает.

Ответ 6

Вам понадобится push_inserter (т.е. вставка, которая выполняет push es в очередь). Насколько мне известно, такого итератора в STL нет. То, что я обычно делаю, грустно возвращается к старой доброй петле.

Если у вас есть смелость, вы можете перевернуть свой собственный итератор, что-то вроде этого:

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);
}

Это всего лишь черновик, но у вас есть идея. Работает с любым контейнером (или, допустимо, контейнерными адаптерами) с помощью метода push (например, queue, stack).

Ответ 7

std::queue не является одним из основных контейнеров в STL. Это контейнерный адаптер, который построен с использованием одного из базовых контейнеров STL (в этом случае один из последовательных контейнеров: std::vector std::deque или std::list). Он разработан специально для поведения FIFO и не обеспечивает случайную вставку на заданном итераторе, который вы хотите для работы insert_iterator. Следовательно, будет невозможно использовать такую ​​очередь.

Самый простой способ, который я мог бы придумать, - это:

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

private:
    std::queue<int>& myQ;
};

И используйте его как:

queue<int> q;
PushFunctor p(q);
std::for_each(v.begin(), v.end(), p);

Ответ 8

В этом простом случае вы можете написать:

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

queue<int, vector<int> > q(v);

Это сделает копию vector и использует ее как базовый контейнер queue.

Конечно, этот подход не будет работать, если вам нужно вставить объекты после создания очереди.

Ответ 9

для c++ 11

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

и c ++ 14

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