std::for_each(A.rbegin(), A.rend(), [](int i) { /*code*/ });
jest proste rozwiązanie.
I zamiast pisało backwards
który zaczyna sekwencję, wydobywa z niej begin
iterator i end
korzystając z bezpłatnego begin
i end
funkcje (z std::begin
i std::end
using
deklaracji pobliżu - pełna ADL), tworzy odwrotne iteratory wokół nich, a następnie zwraca sekwencję z tymi dwoma iteratorami odwrotnymi.
Jest to rodzaj schludne, ponieważ masz taką składnię:
for(int i : backwards(A)) {
// code
}
które łatwiejszy do odczytania niż std::for_each
lub ręcznych for
pętli.
Ale jestem trochę orzechów.
Oto minimalne backwards
. Pełne rozwiązanie lepiej obsługuje adl i kilka przypadków narożnych.
template<class It, class C>
struct range_for_t{
It b,e;
C c; // for lifetime
It begin()const{return b;}
It end()const{return e;}
}
template<class It, class C>
range_for_t<It,C> range_for(It b,It e,C&& c){
return {std::move(b),std::move(e),std::forward<C>(c)};
}
template<class It>
range_for_t<It,int> range_for(It b,It e){
return {std::move(b),std::move(e)};
}
Prosty zakres tylko dla zakresu. Można go ulepszyć dzięki doskonałemu przekazywaniu.
Przechodząc C
jako pojemnik, który może wymagać przedłużenia żywotności. Jeśli zostanie przekazana jako wartość r, zostanie wykonana kopia, w przeciwnym razie tylko odwołanie. W przeciwnym razie nie jest używany.
Następna część jest proste:
template<class It>
auto reverse_it(It it){
return std::reverse_iterator<It>(std::move(it));
}
template<class C>
auto backwards(C&&c){
using std::begin; using std::end;
auto b=begin(c), e=end(c);
return range_for(
reverse_it(e),reverse_it(b),
std::forward<C>(c)
);
}
To niesprawdzone ale powinno działać.
Jeden ważny test jest zapewnienie, że działa po nakarmić vec rvalue jak:
for(auto x:backwards(make_vec()))
prac - czyli co poeksperymentować przechowywania C
chodzi. Zakłada się również, że ruchome iteratory kontenerów mają ładnie zachowujące się iteratory.
Ty odwrócony rend i rbegin. – Borgleader
@Borgleader Tak, masz rację. Dzięki. – user350954