2016-07-21 17 views
10

Załóżmy że 2 (lub więcej) pojemników I mają iterację jednocześnie - na przykład, do obliczania iloczyn skalarny dwóch wektorów:zakres dla pętli z wielu pojemników

std::vector<double> vector1; 
std::vector<double> vector2; // identical size to vector1 

co jest korzystne C + +11 sposób na jednoczesne określenie pętli zasięgu dla obu (lub wszystkich) kontenerów? Czy wymaga to wyboru jednego kontenera/iteratora, aby pisać krótko (tj. for (auto i : c)) w pętli zasięgu, podczas gdy wszystkie inne pojemniki/iteratory muszą być obsługiwane przez długi czas? Czy jest jakiś powód składnia w przyszłości nie może zostać przedłużony do obsługi krótkiej ręki zarówno/wszystkie pojemniki, jak pokazano poniżej ... co wydaje się bardzo czytelny:

double dotProduct(0.0); 
for (auto const & value1 : vector1, auto const & value2 : vector2) // illegal! 
{ 
    dotProduct += value1*value2; 
} 
+3

Możliwy duplikat [Jaki jest najlepszy sposób na powtórzenie dwóch lub więcej kontenerów jednocześnie] (http://stackoverflow.com/questions/12552277/whats-the-best-way-to-iterate-over-two-or -więcej-kontenerów-jednocześnie) – ildjarn

+0

Na powierzchni tak ... ale czy którakolwiek z odpowiedzi tam jest (a) czytelna i (b) ogólna i (c) oparta na standardowym C++? Nie to, co widziałem. Od wczesnych dni C, można napisać 'dla (i = 0, j = 0, k = 0; i omatai

+0

Spójrz na [mitera] (https://github.com/ClaasBontus/miterator). Łatwiej będzie z zakresami, które nie będą przed C++ 20. –

Odpowiedz

7

W innych (często funkcjonalna) języków odbywa się to za pomocą funkcji o nazwie zip. Jako przykład, Python posiada wbudowaną zip że iteracje over jego argumenty i zwraca krotki:

for i in zip([1,2,3], (1,2,3), { 0:0, 1:1, 2:2 }): 
    l,t,d = i 
    print("list item: %d, tuple item %d, dict item %d" % (l,t,d))  

Można użyć biblioteki klasy w C++, aby uzyskać tę funkcjonalność, np Boost.Range lub Eric Niebler's rangev3. Zakresy nie zostały niestety odrzucone w standardzie C++ 17, ale nigdy nie rozpocznę projektu bez biblioteki zakresów. W Boost.Range funkcja nazywa combine:

#include <boost/range/combine.hpp> 
#include <iostream> 
#include <vector> 
#include <list> 

int main(int, const char*[]) 
{ 
    std::vector<int> const v{0,1,2,3,4}; 
    std::list<char> const l{'a', 'b', 'c', 'd', 'e'}; 

    for(auto const& i: boost::combine(v, l)) 
    { 
     int ti; 
     char tc; 
     std::tie(ti,tc) = i; 
     std::cout << '(' << ti << ',' << tv << ')' << '\n'; 
    } 

    return 0; 
} 

z C++ 17 można zastąpić std::tie o strukturze wiązania i usunąć ten rodzaj niezwykłego „inicjalizacji” z std::tie.

for(auto const& [ti,tc] : boost::combine(v, l)) { 
    std::cout << '(' << ti << ',' << tv << ')' << '\n'; 
    } 

Choć żałuję, że zakresy nie są wliczone w C++ 17, myślę, że Wiązania strukturyzowane są doskonałym postęp i będzie poważnie zmienić kod sposób jest napisane. Posiadanie zakresów w standardzie sprawiłoby, że byłyby one bardziej popularne i podniosłyby je z biblioteki innej firmy, w której wiele osób ma zastrzeżenia, ponieważ jest to coś, czego nie znają standardowej funkcji, którą powinien znać programista C++.

+0

Doskonała odpowiedź ... ale trochę rozczarowująca. A czy nie powinno to być 'std :: tie (ti, tc) = i'? To, co uważam za niezadowalające, to nie twoja wina - to wina składni C++, która silnie kieruje się ku (a) łączeniu rzeczy za pomocą (b) trików i (c) pojedynczego iteratora ... zamiast (prostszego) wielokrotnego zsynchronizowanego iteratora . Biorąc pod uwagę oryginalną składnię C pokazaną w moim komentarzu do mojego pytania, jestem zaskoczony, że C++ nie obsługuje 'for (int i = 0, int j = 0; ...)' gdy obsługuje 'for (int i = 0, j = 0; ...) '. Jestem ciekawy, czy istnieje przekonujący powód, dlaczego nie. – omatai

+0

@omatai dlaczego rozczarowujące? Możesz użyć boost :: Combine nawet w kodzie C++ 98. Jeśli chodzi o "sztuczki" - spójrz na wersję Pythona - istnieje również "sztuczka" do łączenia rzeczy, nawet Haskell ma "sztuczkę" zip.I nie sądzę, że to jest wadą - dlaczego zanieczyszczać język materiałami, które można łatwo wprowadzić w bibliotekach? –

+0

Czytelność, bałagan. Gdybym spotkał się z moim sugerowanym (nielegalnym) kodem lub tym kodem w ciągu pięciu lat, natychmiast wiedziałbym, co się dzieje z moją sugestią, i potrzebuję zastosować znacznie więcej inteligencji i skoków wiary, aby to przetrawić (całkowicie ważne) wersja (bez obrazy dla @Jens). Więc jestem rozczarowany nie w tej (całkowicie poprawnej) odpowiedzi, ale w niepowodzeniu składni C++ do obsługi czegoś, co moim zdaniem byłoby prostsze i czystsze. – omatai

Powiązane problemy