2008-11-23 6 views
9

Ich habe einen Container mit Paaren gefüllt. Ich möchte darin mit den generischen STL-Algorithmen iterieren (in meinem Fall wäre es inner_product, aber betrachte es als generisches Problem). Der Algorithmus, den ich verwende, erwartet Iteratoren zuerst und zuletzt. Kann ich spezielle Iteratoren zuerst und zuletzt bereitstellen, die nicht auf den Paaren, sondern auf dem ersten Element jedes Paares iterieren?Bereitstellen eines Iterators für das erste Element eines Containers von Paaren

Ich weiß, dass ich es manuell tun kann, ein handgemachtes Funktionsobjekt zur Verfügung stellend, das ein Wrapper um den Standardcontaineriterator sein wird und es zum ersten Mitglied des Paares des Paares selbst bestimmt, aber ich denke, dass es gibt auch ein cleverer One-Liner, um es für mich zu tun. Was würde es sein?

+0

Sie meinen zum Beispiel, Sie haben eine map.begin(), und Sie möchten über ihre Werte (.second) iterieren? –

+0

Ja, das ist ein weiteres Beispiel für das gleiche Grundproblem. –

+0

ist Boost erlaubt? :) –

Antwort

11

Ich habe mich umgesehen und boost::transform_iterator gefunden. Ich habe diesen Code entwickelt. Erstaunlich, wie gut es funktioniert:

#include <map> 
#include <algorithm> 
#include <iostream> 
#include <string> 
#include <iterator> 
#include <boost/iterator/transform_iterator.hpp> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 

int main() { 
    typedef std::map<std::string, int>::value_type value_type; 
    std::map<std::string, int> a; 
    a["one"] = 1; 
    a["two"] = 2; 

    // returns the second element 
    boost::function<int(value_type&)> f = boost::bind(&value_type::second, _1); 
    std::copy(boost::make_transform_iterator(a.begin(), f), 
       boost::make_transform_iterator(a.end(), f), 
       std::ostream_iterator<int>(std::cout, " ")); 

} 

Es "1 2 " auf die Standardausgabe ist Druck.

+0

Es ist so nah an einer "clever one liner Lösung" wie ich denke, wir werden bekommen ... :-) –

+0

+1: zu spät zu beantworten .... –

+0

Sie * könnte * lege alles in eine Linie. aber Sie müssten den Bind-Aufruf wiederholen. hässlicher code copy'n'paste dann :) –

1

Sie können z. std :: vector :: const_iterator selbst, reinimplementieren von operator * und operator-> um das erste des Paares zurückzugeben. Sie müssen auch Ihre eigenen Funktionen begin() und end() erstellen, um Ihren benutzerdefinierten Iterator zurückzugeben.

Sie können auch zu binären Funktionsklassen erstellen und diese an inner_product übergeben.

+0

Sind Sie sicher, dass ich STL-Iteratoren subclass? Ich habe jedoch immer gesagt, dass sie keine virtuelle Destruktoren zur Verfügung gestellt haben und keine Unterklassen aktiviert haben. –

+0

Ich habe keine Unterklasse std :: iterator gesagt. Ich sagte Unterklasse std :: vector :: const_iterator. Ich habe es gerade jetzt ausprobiert und es funktioniert. – strager

+0

Sie * kann * (Entschuldigung mein Kommentar sagte "kann nicht", ich tatsächlich gemeint "kann") Unterklasse von std :: iterator in der Tat. es stellt die üblichen typedefs zur Verfügung, die benötigt werden. sein Zweck ist es nicht, eine polymorphe Schnittstelle zur Verfügung zu stellen –

1

Es gibt keine clevere One-Liner-Lösung. Ihre beste Hoffnung ist es, einen Wrapper-Iterator zu schreiben. Das ist eigentlich eine schöne kanonische Lösung. Sie können prüfen, ob Boost bereits über das verfügt, was Sie benötigen. Wenn nicht, versuchen Sie, einen generischen Wrapper zu schreiben, der für andere Probleme wiederverwendet werden kann.

Die STL enthält einen solchen Iterator-Wrapper namens reverse_iterator. Der Name impliziert seine Verwendung.

1

Letztendlich denke ich, dass Ihre Idee der richtige Weg ist. Sie können Boost verwenden, um Ihnen dabei zu helfen. Zu Beginn benötigen Sie eine Funktion, die Ihr Paar übernimmt und das erste Element zurückgibt. Ich denke, Sie könnten eine solche Funktion in-line schreiben mit der Lambda library, aber aus Gründen der Lesbarkeit, ich denke, ich würde nur eine einfache Funktion schreiben, die das stattdessen tut. Übergeben Sie dann diese Funktion mit Ihren ursprünglichen Iteratoren, um eine transform_iterator für den Anfang und das Ende Ihrer Sequenz zu konstruieren.

Verwandte Themen