Czy istnieje adapter kontenera, który odwróciłby kierunek iteratorów, dzięki czemu mogę iterować po kontenerze w odwrotnej kolejności za pomocą pętli for opartej na zakresie?
Za pomocą jawnych iteratorów przekonwertowałbym to:
for (auto i = c.begin(); i != c.end(); ++i) { ...
zaangażowany w to:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Chcę przekonwertować to:
for (auto& i: c) { ...
do tego:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Czy istnieje coś takiego, czy muszę to sam napisać?
c++
c++11
ranged-loops
Alex B.
źródło
źródło
begin
doend
, lub do czynienia z iteratorów strumienia i tym podobne. Algorytmy zakresu byłyby świetne, ale tak naprawdę to tylko cukier syntaktyczny (z wyjątkiem możliwości leniwej oceny) w stosunku do algorytmów iteracyjnych.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; };
Można to ulepszyć (dodającconst
wersje itp.), ale działa:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
wydruki321
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Więc możesz po prostu użyćfor(auto &i: reverse_adapt_container(v)) cout << i;
iteracji.parallel_for
byłby cel, z jeszcze silniejszym warunkiem „nie dbam o to, jaki porządek”, gdyby został włączony do normy w jakiejś formie. Oczywiście może mieć również cukier syntaktyczny oparty na zakresie :-)Odpowiedzi:
Zwiększ faktycznie ma taki adapter:
boost::adaptors::reverse
.źródło
W rzeczywistości w C ++ 14 można to zrobić za pomocą kilku wierszy kodu.
Jest to bardzo podobny pomysł do rozwiązania @ Paula. Z powodu braków w C ++ 11 to rozwiązanie jest nieco niepotrzebnie wzdęte (plus definiuje się w standardowych zapachach). Dzięki C ++ 14 możemy uczynić go o wiele bardziej czytelnym.
Kluczową obserwacją jest to, że pętle for oparte na zakresie działają w oparciu o
begin()
iend()
w celu uzyskania iteratorów zakresu. Dzięki ADL , jeden nawet nie trzeba określić ich zwyczajbegin()
iend()
w std :: nazw.Oto bardzo proste rozwiązanie przykładowe:
Działa to jak urok, na przykład:
drukuje zgodnie z oczekiwaniami
UWAGA
std::rbegin()
,std::rend()
istd::make_reverse_iterator()
nie są jeszcze zaimplementowane w GCC-4.9. Piszę te przykłady zgodnie ze standardem, ale nie skompilowałyby się w stabilnym g ++. Niemniej jednak dodawanie tymczasowych kodów pośredniczących dla tych trzech funkcji jest bardzo łatwe. Oto przykładowa implementacja, zdecydowanie niekompletna, ale działa wystarczająco dobrze w większości przypadków:źródło
forward<T>
swojejreverse
realizacji.using namespace std
w nagłówku, co nie jest dobrym pomysłem. A może coś mi brakuje?Powinno to działać w C ++ 11 bez doładowania:
źródło
std
przestrzeni nazw ma niezdefiniowane zachowanie według 17.6.4.2.1.make_reverse_iterator
nie ma wstd
przestrzeni nazw, więc nie będzie kolidować z wersją C ++ 14.Czy to działa dla Ciebie:
źródło
na przykład:
źródło
Jeśli możesz użyć zakresu v3 , możesz użyć adaptera zakresu zwrotnego,
ranges::view::reverse
który umożliwia przeglądanie kontenera w odwrotnej kolejności.Minimalny działający przykład:
Zobacz DEMO 1 .
Uwaga: Według Erica Nieblera ta funkcja będzie dostępna w C ++ 20 . Można tego użyć z
<experimental/ranges/range>
nagłówkiem. Wtedyfor
oświadczenie będzie wyglądać następująco:Zobacz DEMO 2
źródło
ranges::view
przestrzeń nazw została zmieniona naranges::views
. Więc użyjranges::views::reverse
.Jeśli nie używam C ++ 14, znajdę poniżej najprostszego rozwiązania.
Demo .
Nie działa dla kontenerów / typów danych (takich jak tablica), które nie mają
begin/rbegin, end/rend
funkcji.źródło
Możesz po prostu użyć tej
BOOST_REVERSE_FOREACH
iteracji do tyłu. Na przykład kodgeneruje następujące dane wyjściowe:
źródło