Które z poniższych stwierdzeń jest dla Ciebie bardziej czytelne? Ręcznie napisana pętla:
for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
bar.process(*it);
}
Lub wywołanie algorytmu:
#include <algorithm>
#include <functional>
std::for_each(vec.begin(), vec.end(),
std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Zastanawiam się, czy std::for_each
naprawdę warto, biorąc pod uwagę, że tak prosty przykład wymaga już tyle kodu.
Jakie są twoje przemyślenia na ten temat?
c++
algorithms
fredoverflow
źródło
źródło
map(bar.process, vec)
chociaż mapa efektów ubocznych jest odradzana, a lista wyrażeń / wyrażeń generatora jest zalecana zamiast mapy).BOOST_FOREACH
...Odpowiedzi:
Jest powód, dla którego wprowadzono lambdas, i to dlatego, że nawet Standardowy Komitet rozpoznaje, że druga forma jest do bani. Skorzystaj z pierwszego formularza, aż uzyskasz obsługę C ++ 0x i lambda.
źródło
Zawsze używaj wariantu, który najlepiej opisuje to , co zamierzasz zrobić. To jest
Teraz przeanalizujmy przykłady:
My też
for_each
tam mamy - yippeh . Mamy[begin; end)
zasięg, na którym chcemy operować.Zasadniczo algorytm był znacznie bardziej wyraźny i dlatego był lepszy niż jakakolwiek ręczna implementacja. Ale potem ... Segregatory? Memfun? Zasadniczo C ++ interna jak uzyskać funkcję członka? W moim zadaniu nie dbam o nie! Nie chcę też cierpieć z powodu tej pełnej, przerażającej składni.
Teraz inna możliwość:
To prawda, że jest to powszechny wzorzec rozpoznawania, ale ... tworzenie iteratorów, zapętlanie, inkrementacja, dereferencje. To także są rzeczy , których nie obchodzi mnie , aby wykonać swoje zadanie.
Trzeba przyznać, że wygląda lepiej niż waay pierwszego rozwiązania (przynajmniej, pętla ciało jest elastyczne i dość wyraźny), ale nadal, to naprawdę nie jest , że świetnie. Użyjemy tego, jeśli nie mielibyśmy lepszych możliwości, ale może mamy ...
Lepszy sposób?
Teraz z powrotem do
for_each
. Czy nie byłoby wspaniale powiedziećfor_each
i być elastycznym w operacjach, które należy wykonać? Na szczęście, odkąd C ++ 0x lambdas, jesteśmyTeraz, gdy znaleźliśmy abstrakcyjne, ogólne rozwiązanie wielu powiązanych sytuacji, warto zauważyć, że w tym konkretnym przypadku istnieje absolutnie ulubiony numer 1 :
Naprawdę nie może być dużo jaśniejszego niż to. Na szczęście, C ++ 0x get podobna składnia wbudowanej !
źródło
for (const Foo& x : vec) bar.process(x);
lub używa,const auto&
jeśli chcesz.const auto&
jest możliwe? Nie wiedziałem o tym - świetne informacje!Ponieważ to jest tak nieczytelne?
źródło
int
zsize_t
jest niebezpieczne. Ponadto indeksowanie nie działa na przykład z każdym konteneremstd::set
.ogólnie rzecz biorąc, pierwsza forma jest czytelna dla praktycznie każdego, kto wie, czym jest pętla for, bez względu na to, jakie ma doświadczenie.
także ogólnie rzecz biorąc, drugi nie jest wcale tak czytelny: dość łatwe ustalenie, co robi for_each, ale jeśli nigdy nie widziałeś,
std::bind1st(std::mem_fun_ref
nie mogę sobie wyobrazić, że trudno to zrozumieć.źródło
Właściwie nawet przy C ++ 0x nie jestem pewien,
for_each
czy dostanę dużo miłości.Jest o wiele bardziej czytelny.
Jedną z rzeczy, których nie lubię w algorytmach (w C ++) jest to, że ich rozumowanie na iteratorach jest bardzo szczegółowe.
źródło
Gdyby napisać takt jako funktor, byłoby to o wiele prostsze:
Tutaj kod jest dość czytelny.
źródło
Wolę ten drugi, ponieważ jest schludny i czysty. W rzeczywistości jest częścią wielu innych języków, ale w C ++ jest częścią biblioteki. To naprawdę nie ma znaczenia.
źródło
Twierdziłbym, że teraz ten problem nie jest specyficzny dla C ++.
Chodzi o to, że przekazanie funktora do innej funkcji nie ma na celu zastąpienia pętli .
Ma uprościć pewne wzorce, które stają się bardzo naturalne w programowaniu funkcjonalnym, takim jak gość i obserwator , żeby wymienić tylko dwa, które przychodzą mi do głowy natychmiast.
W językach, w których brakuje funkcji pierwszego rzędu (Java jest prawdopodobnie najlepszym przykładem), takie podejścia zawsze wymagają implementacji określonego interfejsu, który jest dość werbalny i zbędny.
Częstym zastosowaniem, które często widzę w innych językach, byłoby:
Zaletą tego jest to, że nie musisz wiedzieć jak
someCollection
jest faktycznie wdrażany ani cosomeUnaryFunctor
robi. Wszystko, co musisz wiedzieć, to żeforEach
metoda zastosuje iterację wszystkich elementów kolekcji, przekazując je do podanej funkcji.Osobiście, jeśli jesteś w stanie, aby mieć wszystkie informacje o strukturze danych, którą chcesz iterować, oraz wszystkie informacje o tym, co chcesz zrobić na każdym etapie iteracji, podejście funkcjonalne nadmiernie komplikuje rzeczy, szczególnie w języku, gdzie jest to pozornie dość nużące.
Należy również pamiętać, że funkcjonalne podejście jest wolniejsze, ponieważ masz wiele połączeń, które kosztują za pewną cenę, których nie masz w pętli for.
źródło
std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun_ref(&Bar::process), bar));
I jest wolniejszy w czasie wykonywania lub kompilacji (jeśli masz szczęście). Nie rozumiem, dlaczego zastąpienie struktur kontroli przepływu wywołaniami funkcji poprawia kod. Każda przedstawiona tutaj alternatywa jest bardziej czytelna.Myślę, że problem polega na tym, że
for_each
tak naprawdę nie jest algorytmem, to po prostu inny (i zwykle gorszy sposób) napisanie ręcznie napisanej pętli. z tej perspektywy powinien to być najmniej używany standardowy algorytm i tak, prawdopodobnie równie dobrze możesz użyć pętli for. jednak rada w tytule nadal obowiązuje, ponieważ istnieje kilka standardowych algorytmów dostosowanych do bardziej specyficznych zastosowań.Tam, gdzie jest algorytm, który ściślej robi to, co chcesz, to tak, powinieneś preferować algorytmy zamiast ręcznie napisanych pętli. oczywistymi przykładami są tutaj sortowanie za pomocą
sort
lubstable_sort
wyszukiwanie za pomocąlower_bound
,upper_bound
lubequal_range
, ale większość z nich ma pewną sytuację, w której lepiej jest używać ich w porównaniu z ręcznie kodowaną pętlą.źródło
W przypadku tego małego fragmentu kodu oba są dla mnie jednakowo czytelne. Ogólnie uważam, że ręczne pętle są podatne na błędy i wolę używać algorytmów, ale tak naprawdę zależy to od konkretnej sytuacji.
źródło