Gibt es einen Container-Adapter, der die Richtung der Iteratoren umkehren würde, so dass ich über einen Container in umgekehrter Richtung mit Bereich-basierte for-Schleife iterieren kann?
Bei expliziten Iteratoren würde ich dies umsetzen:
for (auto i = c.begin(); i != c.end(); ++i) { ...
in diese:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Ich möchte dies umwandeln:
for (auto& i: c) { ...
dazu:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Gibt es so etwas, oder muss ich es selbst schreiben?
22 Stimmen
Ein Reverse-Container-Adapter klingt interessant, aber ich denke, Sie müssen ihn selbst schreiben. Wir hätten dieses Problem nicht, wenn sich das Standardkomitee beeilen würde und bereichsbasierte Algorithmen anstelle von expliziten Iteratoren anpassen würde.
0 Stimmen
@Seth Ich weiß, ich könnte es schreiben, aber das ist nicht der Punkt. Wenn ich es schreibe, wird es zu einer dieser Utility Functions That Don't Belong Anywhere In Particular(tm), so dass du am Ende deinen Code mit dem Include eines besagten Utility-Headers bestreust und dein Build-System umstellst, um es projektübergreifend zu nutzen. Mit dieser Argumentation sollten wir immer noch BOOST_FOREACH anstelle von range-for verwenden. Und ja, ich bin faul.
5 Stimmen
@deft_code: "anstelle von?" Warum sollten Sie Iterator-basierte Algorithmen abschaffen wollen? Sie sind viel besser und weniger langatmig für Fälle, in denen man keine Iteration von
begin
aend
oder für den Umgang mit Stream-Iteratoren und Ähnlichem. Bereichsalgorithmen wären großartig, aber sie sind wirklich nur syntaktischer Zucker (abgesehen von der Möglichkeit der trägen Auswertung) für Iterator-Algorithmen.20 Stimmen
@deft_code
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; };
Sie 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;
druckt321
11 Stimmen
@SethCarnegie: Und um eine schöne funktionale Form hinzuzufügen:
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Sie können also einfach Folgendes verwendenfor(auto &i: reverse_adapt_container(v)) cout << i;
zu iterieren.1 Stimmen
Auch wenn die bereichsbasierte for-Schleife so definiert ist, dass sie fortlaufend von
begin
aend
Ich denke, semantisch gesehen bedeutet es, dass die Reihenfolge der Operation nicht wichtig ist.2 Stimmen
@C.R: Ich glaube nicht, dass es なければならない meinen, denn dann wäre sie als prägnante Syntax für Schleifen, bei denen die Reihenfolge eine Rolle spielt, nicht mehr verfügbar. IMO ist die Prägnanz wichtiger/nützlicher als die semantische Bedeutung, aber wenn Sie keinen Wert auf die Prägnanz legen, kann Ihr Styleguide ihr jede beliebige Bedeutung geben. Das ist in etwa das, was
parallel_for
wäre, mit einer noch stärkeren "Es ist mir egal, in welcher Reihenfolge"-Bedingung, wenn sie in irgendeiner Form in die Norm aufgenommen würde. Natürlich könnte es auch einen bereichsbezogenen syntaktischen Zucker geben :-)