399 Stimmen

C++11 Umgekehrte bereichsbasierte for-Schleife

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 a end 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.

12voto

IceFire Punkte 3870

Sorry, aber mit aktuellen C++ (abgesehen von C++20) alle diese Lösungen scheinen zu sein minderwertig zu verwenden, nur Index-basierte für. Nichts hier ist nur "ein paar Zeilen Code". Also, ja: Iteration über eine einfache int-Schleife. Das ist die beste Lösung.

0 Stimmen

Index oder eine einfache rbegin() / rend() .

0 Stimmen

@AlexisWilke ja, OP hat es selbst erwähnt, aber eigentlich: einverstanden! Besonders mit std::rbegin/std::rend kann es sogar für Arrays verwendet werden

11voto

Arlen Punkte 6437

Funktioniert das für Sie?

#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>

int main(int argc, char* argv[]){

  typedef std::list<int> Nums;
  typedef Nums::iterator NumIt;
  typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
  typedef boost::iterator_range<NumIt> irange_1;
  typedef boost::iterator_range<RevNumIt> irange_2;

  Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
  irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
  irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );

  // prints: 1 2 3 4 5 6 7 8 
  for(auto e : r1)
    std::cout << e << ' ';

  std::cout << std::endl;

  // prints: 8 7 6 5 4 3 2 1
  for(auto e : r2)
    std::cout << e << ' ';

  std::cout << std::endl;

  return 0;
}

9voto

Khan Lau Punkte 91
template <typename C>
struct reverse_wrapper {

    C & c_;
    reverse_wrapper(C & c) :  c_(c) {}

    typename C::reverse_iterator begin() {return c_.rbegin();}
    typename C::reverse_iterator end() {return c_.rend(); }
};

template <typename C, size_t N>
struct reverse_wrapper< C[N] >{

    C (&c_)[N];
    reverse_wrapper( C(&c)[N] ) : c_(c) {}

    typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
    typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};

template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
    return reverse_wrapper<C>(c);
}

z. B:

int main(int argc, const char * argv[]) {
    std::vector<int> arr{1, 2, 3, 4, 5};
    int arr1[] = {1, 2, 3, 4, 5};

    for (auto i : r_wrap(arr)) {
        printf("%d ", i);
    }
    printf("\n");

    for (auto i : r_wrap(arr1)) {
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}

1 Stimmen

Können Sie Ihre Antwort bitte näher erläutern?

0 Stimmen

Dies ist eine umgekehrte Bereichs-Basis-Schleife der C++11-Klasse tamplate

4voto

Catriel Punkte 324

Sie könnten einfach Folgendes verwenden BOOST_REVERSE_FOREACH die rückwärts iteriert. Zum Beispiel, der Code

#include <iostream>
#include <boost\foreach.hpp>

int main()
{
    int integers[] = { 0, 1, 2, 3, 4 };
    BOOST_REVERSE_FOREACH(auto i, integers)
    {
        std::cout << i << std::endl;
    }
    return 0;
}

erzeugt die folgende Ausgabe:

4

3

2

1

0

2voto

iammilind Punkte 64857

Wenn Sie nicht C++14 verwenden, finde ich unten die einfachste Lösung.

#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
  T& m_T;

  METHOD(begin());
  METHOD(end());
  METHOD(begin(), const);
  METHOD(end(), const);
};
#undef METHOD

template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }

Demo .
Es funktioniert nicht für die Container/Datentypen (wie Array), die nicht über begin/rbegin, end/rend Funktionen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X