C ++ 11 bietet mehrere Möglichkeiten zum Durchlaufen von Containern. Beispielsweise:
Bereichsbasierte Schleife
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
Was ist jedoch die empfohlene Methode, um zwei (oder mehr) Container derselben Größe zu durchlaufen, um Folgendes zu erreichen:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
memecs
quelle
quelle
transform
Gegenwart in#include <algorithm>
?containerA = containerB;
anstelle der Schleife.Antworten:
Eher zu spät zur Party. Aber: Ich würde über Indizes iterieren. Aber nicht mit der klassischen
for
Schleife, sondern mit einer bereichsbasiertenfor
Schleife über den Indizes:indices
ist eine einfache Wrapper-Funktion, die einen (träge ausgewerteten) Bereich für die Indizes zurückgibt. Da die Implementierung - obwohl einfach - etwas zu lang ist, um sie hier zu veröffentlichen, finden Sie eine Implementierung auf GitHub .Dieser Code ist so effizient wie die Verwendung einer manuellen, klassischen
for
Schleife.Wenn dieses Muster in Ihren Daten häufig vorkommt, sollten Sie ein anderes Muster verwenden, das aus
zip
zwei Sequenzen besteht und eine Reihe von Tupeln erzeugt, die den gepaarten Elementen entsprechen:Die Implementierung von
zip
bleibt als Übung für den Leser, folgt aber leicht aus der Implementierung vonindices
.(Vor C ++ 17 müssten Sie stattdessen Folgendes schreiben :)
quelle
boost::counting_range(size_t(0), containerA.size())
indices
Implementierung eine Compiler-Ausgabe liefert, die mit der Verwendung manuellerfor
Schleifen identisch ist . Es gibt überhaupt keinen Overhead.Verwenden Sie für Ihr spezielles Beispiel einfach
Für den allgemeineren Fall können Sie Boost.Iterator
zip_iterator
mit einer kleinen Funktion verwenden, um es in bereichsbasierten for-Schleifen verwendbar zu machen. In den meisten Fällen funktioniert dies:Live-Beispiel.
Für eine ausgewachsene Großzügigkeit möchten Sie jedoch wahrscheinlich mehr davon , die für Arrays und benutzerdefinierte Typen korrekt funktionieren , die nicht Mitglied haben
begin()
/end()
aber sie habenbegin
/end
Funktionen in ihrem Namensraum. Auf diese Weise kann der Benutzer auchconst
über diezip_c...
Funktionen gezielt darauf zugreifen .Und wenn Sie wie ich ein Verfechter netter Fehlermeldungen sind, dann möchten Sie wahrscheinlich diese , die prüft, ob temporäre Container an eine der
zip_...
Funktionen übergeben wurden, und wenn ja, eine nette Fehlermeldung ausgibt.quelle
auto
genauso funktioniert wie ein Vorlagenparameter.T&&
In einer Vorlage befindet sich eine universelle Referenz, wie im ersten Link erläutert. Sieauto&& v = 42
wird also als abgeleitetint&&
undauto&& w = v;
dann als abgeleitetint&
. Sie können sowohl l-Werte als auch r-Werte abgleichen und beide veränderbar machen, ohne eine Kopie zu erstellen.zip_range
.Ich frage mich, warum niemand dies erwähnt hat:
PS: Wenn die Containergrößen nicht übereinstimmen, müssen Sie den Code in die if-Anweisungen einfügen.
quelle
Es gibt viele Möglichkeiten, bestimmte Dinge mit mehreren Containern zu tun, wie im
algorithm
Header angegeben. In dem Beispiel, das Sie gegeben haben, könnten Sie beispielsweise verwendenstd::copy
anstelle einer expliziten for-Schleife verwenden.Auf der anderen Seite gibt es keine integrierte Möglichkeit, mehrere Container generisch zu iterieren, außer einer normalen for-Schleife. Dies ist nicht überraschend, da es viele Möglichkeiten zum Iterieren gibt. Denken Sie darüber nach: Sie könnten einen Container mit einem Schritt durchlaufen, einen Container mit einem anderen Schritt; oder durch einen Behälter bis zum Ende und dann mit dem Einsetzen beginnen, während Sie bis zum Ende des anderen Behälters gehen; oder ein Schritt des ersten Containers für jedes Mal, wenn Sie den anderen Container vollständig durchlaufen und dann von vorne beginnen; oder ein anderes Muster; oder mehr als zwei Behälter gleichzeitig; etc ...
Wenn Sie jedoch Ihre eigene Funktion "for_each" erstellen möchten, die zwei Container nur bis zur Länge des kürzesten durchläuft , können Sie Folgendes tun:
Natürlich können Sie auf ähnliche Weise jede Art von Iterationsstrategie erstellen, die Sie möchten.
Natürlich könnten Sie argumentieren, dass es einfacher ist, die innere for-Schleife direkt auszuführen, als eine benutzerdefinierte Funktion wie diese zu schreiben ... und Sie hätten Recht, wenn Sie dies nur ein oder zwei Mal tun würden. Aber das Schöne ist, dass dies sehr wiederverwendbar ist. =)
quelle
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
aber der Compiler schreit. Kann jemand erklären, warum dies ungültig ist?for (int x = 0, y = 0; ...
funktioniert, aberfor (int x = 0, double y = 0; ...)
nicht.typename...
Für den Fall, dass Sie nur über 2 Container gleichzeitig iterieren müssen, gibt es eine erweiterte Version des Standardalgorithmus for_each in der Boost-Bereichsbibliothek, z.
Wenn Sie mehr als 2 Container in einem Algorithmus verarbeiten müssen, müssen Sie mit zip spielen.
quelle
Eine andere Lösung könnte darin bestehen, eine Referenz des Iterators des anderen Containers in einem Lambda zu erfassen und einen Post-Inkrement-Operator zu verwenden. Zum Beispiel wäre eine einfache Kopie:
In Lambda können Sie alles tun
ita
und es dann erhöhen. Dies erstreckt sich leicht auf den Fall mehrerer Behälter.quelle
Eine Bereichsbibliothek bietet diese und andere sehr hilfreiche Funktionen. Im folgenden Beispiel wird Boost.Range verwendet . Eric Nieblers rangev3 sollte eine gute Alternative sein.
C ++ 17 macht dies mit strukturierten Bindungen noch besser:
quelle
delme.cxx:15:25: error: no match for 'operator=' (operand types are 'std::tuple<int&, char&>' and 'const boost::tuples::cons<const int&, boost::tuples::cons<const char&, boost::tuples::null_type> >') std::tie(ti,tc) = i;
^19.13.26132.0
und Windows SDK-Version10.0.16299.0
):error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const boost::tuples::cons<const char &,boost::fusion::detail::build_tuple_cons<boost::fusion::single_view_iterator<Sequence,boost::mpl::int_<1>>,Last,true>::type>' (or there is no acceptable conversion)
boost::combine
: stackoverflow.com/q/55585723/8414561Ich bin auch ein bisschen spät dran; Sie können dies jedoch verwenden (Variadic-Funktion im C-Stil):
oder dies (unter Verwendung eines Funktionsparameterpakets):
oder dies (unter Verwendung einer in Klammern eingeschlossenen Initialisierungsliste):
oder Sie können Vektoren wie hier verbinden: Wie können zwei Vektoren am besten verkettet werden? und dann über großen Vektor iterieren.
quelle
Hier ist eine Variante
Anwendungsbeispiel
quelle