C ++ 11 zapewnia wiele sposobów iteracji po kontenerach. Na przykład:
Pętla oparta na zakresie
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
Jednak jaki jest zalecany sposób iteracji na dwóch (lub więcej) kontenerach tego samego rozmiaru, aby osiągnąć coś takiego:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
memeki
źródło
źródło
transform
prezentem w#include <algorithm>
?containerA = containerB;
zamiast pętli.Odpowiedzi:
Raczej późno na przyjęcie. Ale: chciałbym iterować po indeksach. Ale nie z klasyczną
for
pętlą, ale zamiast tego zfor
pętlą opartą na zakresie na indeksach:indices
to prosta funkcja opakowująca, która zwraca (leniwie oceniany) zakres indeksów. Ponieważ implementacja - choć prosta - jest trochę za długa, aby ją tutaj opublikować, możesz znaleźć implementację na GitHub .Ten kod jest tak samo wydajny, jak użycie ręcznej, klasycznej
for
pętli.Jeśli ten wzorzec często występuje w danych, rozważ użycie innego wzorca, który
zip
składa się z dwóch sekwencji i tworzy zakres krotek odpowiadających sparowanym elementom:Implementację
zip
pozostawia się czytelnikowi jako ćwiczenie, ale łatwo wynika z implementacjiindices
.(Przed C ++ 17 musiałbyś zamiast tego napisać:)
źródło
boost::counting_range(size_t(0), containerA.size())
indices
implementacji daje dane wyjściowe kompilatora, które są identyczne z użyciem ręcznychfor
pętli. Nie ma żadnych kosztów ogólnych.Aby uzyskać konkretny przykład, po prostu użyj
W bardziej ogólnym przypadku możesz użyć Boost.Iterator
zip_iterator
, z małą funkcją, dzięki której można go używać w pętlach opartych na zakresie. W większości przypadków zadziała to:Przykład na żywo.
Jednak dla pełnowymiarową genericity, prawdopodobnie chcesz coś bardziej jak ten , który będzie działał prawidłowo dla tablic i typów zdefiniowanych przez użytkownika, które nie mają elementu
begin()
/end()
ale nie mająbegin
/end
funkcje w ich nazw. Pozwoli to również użytkownikowi uzyskać konkretnyconst
dostęp za pośrednictwemzip_c...
funkcji.A jeśli jesteś zwolennikiem ładnych komunikatów o błędach, tak jak ja, prawdopodobnie chcesz tego , który sprawdza, czy jakiekolwiek tymczasowe kontenery zostały przekazane do którejkolwiek z
zip_...
funkcji, i wyświetla ładny komunikat o błędzie, jeśli tak.źródło
auto
działa dokładnie tak samo jak parametr szablonu, awT&&
szablonie jest uniwersalnym odniesieniem, jak wyjaśniono w pierwszym linku, więcauto&& v = 42
zostanie wydedukowany jako,int&&
aauto&& w = v;
następnie zostanie wydedukowany jakoint&
. Pozwala dopasować lvalues, a także rvalues i pozwolić, aby oba były zmienne, bez tworzenia kopii.zip_range
.zastanawiam się, dlaczego nikt o tym nie wspomniał:
PS: jeśli rozmiary kontenerów nie są zgodne, będziesz musiał umieścić kod w instrukcjach if.
źródło
Istnieje wiele sposobów wykonywania określonych czynności z wieloma kontenerami, jak podano w
algorithm
nagłówku. Na przykład w podanym przykładzie możesz użyćstd::copy
zamiast jawnej pętli for.Z drugiej strony nie ma żadnego wbudowanego sposobu na generalne iterowanie wielu kontenerów poza zwykłą pętlą for. Nie jest to zaskakujące, ponieważ istnieje wiele sposobów iteracji. Pomyśl o tym: możesz iterować przez jeden kontener jednym krokiem, jeden kontener drugim krokiem; lub przez jeden pojemnik, aż dotrze do końca, a następnie zacznij wkładać, przechodząc do końca drugiego pojemnika; lub jeden krok pierwszego pojemnika za każdym razem, gdy całkowicie przejdziesz przez drugi pojemnik, a następnie zacznij od nowa; lub inny wzór; lub więcej niż dwa pojemniki jednocześnie; itp ...
Jeśli jednak chcesz stworzyć własną funkcję w stylu „for_each”, która iteruje przez dwa kontenery tylko do długości najkrótszego, możesz zrobić coś takiego:
Oczywiście w podobny sposób możesz stworzyć dowolną strategię iteracji.
Oczywiście możesz argumentować, że po prostu wykonanie wewnętrznej pętli for bezpośrednio jest łatwiejsze niż napisanie niestandardowej funkcji, takiej jak ta ... i miałbyś rację, jeśli zamierzasz to zrobić tylko jeden lub dwa razy. Ale fajną rzeczą jest to, że jest to wielokrotnego użytku. =)
źródło
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
ale kompilator krzyczy. Czy ktoś może wyjaśnić, dlaczego to jest nieważne?for (int x = 0, y = 0; ...
działa, alefor (int x = 0, double y = 0; ...)
nie.typename...
W przypadku, gdy potrzebujesz iterować jednocześnie tylko na 2 kontenerach, istnieje rozszerzona wersja standardu algorytmu for_each w bibliotece zakresu boost, np .:
Kiedy musisz obsłużyć więcej niż 2 pojemniki w jednym algorytmie, musisz bawić się zipem.
źródło
innym rozwiązaniem mogłoby być przechwycenie referencji iteratora drugiego kontenera w lambdzie i użycie do tego operatora postinkrementacji. na przykład prosta kopia to:
wewnątrz lambdy możesz zrobić cokolwiek,
ita
a następnie ją zwiększyć. To łatwo rozciąga się na skrzynię z wieloma kontenerami.źródło
Biblioteka zakresów zapewnia tę i inne bardzo pomocne funkcje. Poniższy przykład używa Boost.Range . Rangev3 Erica Nieblera powinien być dobrą alternatywą.
C ++ 17 uczyni to jeszcze lepszym dzięki powiązaniom strukturalnym:
źródło
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
i Windows SDK10.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/8414561Jestem trochę spóźniony; ale możesz użyć tej (funkcji wariadycznej w stylu C):
lub to (używając pakietu parametrów funkcji):
lub to (używając listy inicjalizującej w nawiasach klamrowych):
lub możesz łączyć wektory, jak tutaj: Jaki jest najlepszy sposób łączenia dwóch wektorów? a następnie iteruj po dużym wektorze.
źródło
Oto jeden wariant
Przykładowe użycie
źródło