Gibt es einen Containeradapter, der die Richtung der Iteratoren umkehrt, damit ich mit einer bereichsbasierten for-Schleife in umgekehrter Reihenfolge über einen Container iterieren kann?
Mit expliziten Iteratoren würde ich Folgendes konvertieren:
for (auto i = c.begin(); i != c.end(); ++i) { ...
das sehr gut finden:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Ich möchte dies konvertieren:
for (auto& i: c) { ...
dazu:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Gibt es so etwas oder muss ich es selbst schreiben?
c++
c++11
ranged-loops
Alex B.
quelle
quelle
begin
bis iterierenend
, oder für den Umgang mit Stream-Iteratoren und dergleichen. Bereichsalgorithmen wären großartig, aber sie sind wirklich nur syntaktischer Zucker (mit Ausnahme der Möglichkeit einer verzögerten Bewertung) gegenüber Iteratoralgorithmen.template<typename T> class reverse_adapter { public: reverse_adapter(T& c) : c(c) { } typename T::reverse_iterator begin() { return c.rbegin(); } typename T::reverse_iterator end() { return c.rend(); } private: T& c; };
Es kann verbessert werden (Hinzufügen vonconst
Versionen usw.), aber es funktioniert:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
Drucke321
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Dann können Sie einfachfor(auto &i: reverse_adapt_container(v)) cout << i;
zum Iterieren verwenden.parallel_for
genau das, wofür es wäre, mit einer noch stärkeren Bedingung "Es ist mir egal, welche Reihenfolge", wenn es in irgendeiner Form in den Standard aufgenommen würde. Natürlich könnte es auch einen Range-basierten syntaktischen Zucker geben :-)Antworten:
Eigentlich hat Boost einen solchen Adapter :
boost::adaptors::reverse
.quelle
Tatsächlich kann dies in C ++ 14 mit sehr wenigen Codezeilen durchgeführt werden.
Dies ist eine sehr ähnliche Idee wie die Lösung von @ Paul. Aufgrund von Dingen, die in C ++ 11 fehlen, ist diese Lösung etwas unnötig aufgebläht (plus Definition in Standardgerüchen). Dank C ++ 14 können wir es viel lesbarer machen.
Die wichtigste Beobachtung ist, dass bereichsbasierte for-Schleifen funktionieren, indem sie sich auf die Iteratoren des Bereichs verlassen
begin()
und dieseend()
erfassen. Dank ADL muss man nicht einmal ihre benutzerdefiniertenbegin()
und definierenend()
im std :: Namespace definieren.Hier ist eine sehr einfache Beispiellösung:
Das funktioniert wie ein Zauber, zum Beispiel:
druckt wie erwartet
HINWEIS
std::rbegin()
,std::rend()
undstd::make_reverse_iterator()
ist noch nicht in GCC-4.9 implementiert. Ich schreibe diese Beispiele gemäß dem Standard, aber sie würden nicht in stabilem g ++ kompiliert. Das Hinzufügen temporärer Stubs für diese drei Funktionen ist jedoch sehr einfach. Hier ist eine Beispielimplementierung, die definitiv nicht vollständig ist, aber in den meisten Fällen gut genug funktioniert:quelle
forward<T>
in Ihrerreverse
Implementierung vergessen .using namespace std
in einem Header, was keine gute Idee ist. Oder fehlt mir etwas?Dies sollte in C ++ 11 ohne Boost funktionieren:
quelle
std
Namespace hat gemäß 17.6.4.2.1 ein undefiniertes Verhalten.make_reverse_iterator
befindet sich nicht imstd
Namespace, sodass es nicht zu Konflikten mit der C ++ 14-Version kommt.Geht das für dich:
quelle
z.B:
quelle
Wenn Sie Range v3 verwenden können , können Sie den Reverse Range Adapter verwenden
ranges::view::reverse
, mit dem Sie den Container in umgekehrter Reihenfolge anzeigen können.Ein minimales Arbeitsbeispiel:
Siehe DEMO 1 .
Hinweis: Laut Eric Niebler ist diese Funktion in C ++ 20 verfügbar . Dies kann mit dem
<experimental/ranges/range>
Header verwendet werden. Dannfor
sieht die Aussage folgendermaßen aus:Siehe DEMO 2
quelle
ranges::view
Namespace wurde in umbenanntranges::views
. Also, benutzeranges::views::reverse
.Wenn ich C ++ 14 nicht benutze, finde ich unten die einfachste Lösung.
Demo .
Es funktioniert nicht für Container / Datentypen (wie Array), die keine
begin/rbegin, end/rend
Funktionen haben.quelle
Sie können einfach verwenden,
BOOST_REVERSE_FOREACH
was rückwärts iteriert. Zum Beispiel der Codegeneriert die folgende Ausgabe:
quelle