2009-11-12 7 views
14

Ich möchte std :: Kopie verwenden Elemente in eine Warteschlange wie folgt einzufügen:Legen Sie in eine STL Warteschlange std :: kopieren

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

Aber dies nicht zu kompilieren, beschweren, dass ‚begin‘ ist kein Mitglied von 'std :: queue'.

Hinweis: Ich habe es mit std::inserter auch versucht - dies ist auch fehlgeschlagen, dieses Mal sagen, dass "Referenz" kein Mitglied von "std :: queue" ist. std::back_inserter und std::back_insert_iterator schlagen ebenfalls mit demselben Fehler fehl.

Fehle ich etwas offensichtliches, oder funktioniert insert_iterator s einfach nicht mit Warteschlangen?

+0

Obwohl die Antworten, die Sie bekommen haben, sind gut, ich persönlich würde nur std :: Warteschlange und andere verkrüppelte Behälteradapter vermeiden. – Kylotan

+0

Ja, sbi und Naveens Vorschlag, eine Deque zu verwenden, wäre eine gute Alternative. –

Antwort

17

‚passt‘ Leider std::queue die Funktion als push_back bekannt nur push was bedeutet, dass die Standard-back_insert_iterator funktioniert nicht.

Wahrscheinlich ist der einfachste Weg (wenn auch konzeptionell hässlich), den Container-Adapter mit einem kurzlebigen Container-Adapter-Adapter (sugh) anzupassen, der so lange wie der Back-Insert-Iterator lebt.

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

wie folgt verwendet:

std::queue<int> qi; 

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

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

Genie. Ordentlich, schön und macht die seltsame Entscheidung deutlich, den Namen push anstelle von push_back zu verwenden. –

+2

Es ist nicht "Pushback", weil der Punkt, an dem die Einfügungen passieren, konzeptuell nicht von Bedeutung sind. Was würde 'push_back' für eine' priority_queue' bedeuten? – UncleBens

+1

Konzeptionell macht es Sinn, ich habe die Arbeit nur "leider" benutzt, weil es bedeutet, dass es den 'back_insert_iterator' abschließt, der wirklich nützlich sein könnte. –

3

std::queue ist kein Container im STL Sinn, es ist ein Container Adapter mit sehr eingeschränkter Funktionalität. Für das, was Sie scheinen entweder std::vector oder std::deque ("Deque, die ein‚echten Container‘) zu müssen, scheint die richtige Wahl.

+0

Oder verwenden Sie eine for-Schleife, um in die Warteschlange zu schieben. Was ich tue, scheint jedoch nicht unvernünftig zu sein, oder? –

+0

Nicht ist es nicht. Sehen Sie Franks Antwort, wie Sie erreichen können, was Sie wollen. – sbi

+0

Nein, tut es nicht (funktional), aber Sie müssen leider Ihren eigenen Inserter rollen. –

6

Queue nicht Iteration durch die Elemente erlaubt.

Von der SGI STL Docs:

eine Warteschlange ist ein Adapter, der eine Teilmenge von beschränkt Container Funktionalität A-Warteschlange eine "first in first out " (FIFO) Datenstruktur 1 das EL bietet, ist,. Elemente werden zur Rückseite der Warteschlange hinzugefügt und können von vorne entfernt werden ; Q.front() ist das Element , das zuletzt zur Warteschlange hinzugefügt wurde. Die Warteschlange erlaubt keine Iteration durch ihre Elemente. [2]

Sie können diese Arbeit machen, aber man kann nicht Verwendung insert_iterator. Sie müssen etwas wie queue_inserter schreiben, das eine Iterator-Schnittstelle darstellt.

Update Ich konnte mir nicht helfen und entschloss mich zu versuchen, den Iterator zu implementieren, den Sie brauchen. Hier sind die Ergebnisse:

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

Dies funktioniert gut für Funktionen wie folgt aus:

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

Aber es ist nicht mit dem STL Kopie funktioniert, da die STL ist dumm.

+1

Andy versucht nicht, durch die Warteschlange zu iterieren, sondern an sie anzuhängen. – sbi

+0

Ja, aber ich brauche ein iteratorähnliches Ding, um es hineinschieben zu können. –

+1

Sonst ist deine Antwort vernünftig. ':)' +1 – sbi

2

Was Sie brauchen, ist ein push_inserter (d. H. Ein Inserter, der push es in die Warteschlange führt). Soweit ich weiß, gibt es keinen solchen Iterator in der STL. Was ich normalerweise tue, ist traurigerweise auf die gute alte For-Schleife zurückzuführen.

Wenn Sie den Mut haben, können Sie Ihre eigenen Iterator, etwas in dieser Richtung rollen:

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

Dies ist nur ein Entwurf ist, aber Sie auf die Idee kam. Arbeitet mit jedem Container (oder, naja, Containeradapter) mit einer push-Methode (z.B.queue, stack).

+0

Es heißt "Back Inserter" in der STL und Sie erhalten einen von "Back_Inserter". Dies funktioniert jedoch nicht in 'std :: queue'. – sbi

+1

Ich weiß, was ein back_insert_iterator ist: ein Iterator, der push_back in einen Container ausführt. Die Warteschlange hat keine push_back-Methode, weshalb back_insert_iterator nicht funktioniert. Die Methode zum Hinzufügen von Elementen in einer Warteschlange ist Push, daher die Idee push_insert_iterator ... –

+0

@sbi: Wenn man bedenkt, dass ein Element in eine Warteschlange über die Funktion queue :: push() eingefügt wird, ist "push_inserter" kein a schlechter Name, IMHO –

1

std::queue ist nicht einer der Grundcontainer in STL. Es ist ein Container-Adapter, der mit einem der Basis-STL-Container (in diesem Fall einer der Sequentiellen Container std::vectorstd::deque oder std::list) gebaut wird. Es wurde speziell für das FIFO-Verhalten entwickelt und bietet keine zufällige Einfügung in den angegebenen Iterator, der für die insert_iterator funktionieren soll. Daher wird es nicht möglich sein, eine Warteschlange wie diese zu verwenden.

Der einfachste Weg, ich dies zu tun denken könnte, ist zu:

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

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

Und verwenden Sie es mögen:

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

Dies ist auch eine großartige Idee. –

3

Ich bin ziemlich sicher, es wird einfach nicht funktionieren - ein queue liefert push, aber ein Insert-Iterator erwartet die Verwendung von push_front oder push_back. Es gibt keinen wirklichen Grund, warum Sie nicht Ihre eigene push_insert_iterator schreiben könnte (oder welchen Namen Sie bevorzugen), aber es ist ein bisschen wie ein Schmerz ist ...

0

In diesem einfachen Fall, können Sie schreiben:

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

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

Dies wird eine Kopie der vector und verwenden Sie es als zugrunde liegenden Container der queue.

Natürlich funktioniert dieser Ansatz nicht, wenn Sie Dinge in die Warteschlange einreihen müssen, nachdem die Warteschlange erstellt wurde.

+0

Sehr guter Punkt. Leider war mein Beispiel zu vereinfacht und das möchte ich nicht machen. –

+2

Warteschlange kann keinen Vektor verwenden. Der Container muss 'pop_front' unterstützen. – UncleBens

+0

Argh! Du hast recht. Aufgrund von Vorlagen hat mein Test dies nicht gezeigt. Nun, ich schätze, Sie können immer noch eine Warteschlange erstellen, mit der Sie 'front()' und 'back()' überprüfen können ...: P – Thomas

3

insert_iterator und back_insert_iterator nur an Behältern (oder Adapter) arbeiten mit (jeweils) insert und push_back Methoden - queue nicht diese haben.

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

Es sei denn, so etwas bereits existiert, aber ich bin mir ziemlich sicher, dass dies nicht der Fall: Sie könnten Ihr eigenes Iterator Vorbild diese, so etwas schreiben.

+0

Ich wollte gerade diese Antwort akzeptieren, die ausgezeichnet aussieht (obwohl ich nicht habe es versucht), aber Charles hat dich auf die Post geschlagen. –

+0

Es wäre schön, einen solchen Iterator in der Standardbibliothek zu haben. In Bezug auf Ihre Implementierung wäre es jedoch sicherer, wenn der Dereferenzierungsoperator ein Proxy-Objekt anstelle des aktuellen Objekts zurückgibt. Tatsächlich erlaubt der Code, so wie er ist, 'push_iterator > it; it = 42; ', was falsch ist (es erlaubt Ihnen auch,' ****** es' zu tun, was nicht korrekter ist). Der 'Operator *' sollte ein Objekt zurückgeben, das den Operator '' definiert. –

+0

Sie könnten Ihrer Antwort auch die übliche Hilfsfunktion hinzufügen, die es Ihnen ermöglicht, den Containertyp wegzulassen: 'template push_iterator < Container > pusher (Container & c) {return push_iterator < Container > (c); } '. –

Verwandte Themen