2011-01-13 21 views
31

Zastanawiam się, gdzie powinniśmy użyć wyrażenia lambda w stosunku do funktora w C++. Dla mnie te dwie techniki są w zasadzie takie same, nawet funktor jest bardziej elegancki i czystszy niż lambda. Na przykład, jeśli chcę ponownie użyć mojego predykatu, muszę wielokrotnie kopiować część lambda. Kiedy więc lambda naprawdę wchodzi na miejsce?Lambda Expression vs Functor w C++

+1

BTW, nie wiem, że wstawiłbym "lambda" jako kod. To nie jest słowo kluczowe lub typ w C++. Jest coś takiego jak "wyrażenie lambda", ale "lambda" nie jest czymś, co zobaczyłbyś w kodzie, chyba że korzystałeś z biblioteki lambda boost lub faktycznie miałeś coś, co nazywa się tym w twoim własnym kodzie. –

+0

@ Noah Roberts: dzięki za wskazanie tego. Edytowane! Chciałem podkreślić to słowo. – Chan

Odpowiedz

12

1) To banalne, a próba udostępnienia go to więcej pracy niż korzyści.

2) Definiowanie funktora po prostu dodaje złożoności (z powodu konieczności zrobienia paczki zmiennych członków i bzdur).

Jeśli żadna z tych rzeczy nie jest prawdziwa, może powinieneś pomyśleć o zdefiniowaniu funktora.

Edytuj: wydaje się, że potrzebujesz przykładu, kiedy byłoby miło użyć lambda na funktorze. Proszę bardzo:

typedef std::vector< std::pair<int,std::string> > whatsit_t; 

int find_it(std::string value, whatsit_t const& stuff) 
{ 
    auto fit = std::find_if(stuff.begin(), stuff.end(), [value](whatsit_t::value_type const& vt) -> bool { return vt.second == value; }); 

    if (fit == stuff.end()) throw std::wtf_error(); 

    return fit->first; 
} 

Bez lambdas trzeba by użyć czegoś, podobnie konstruuje funktora na miejscu lub napisać zewnętrznie skorelowane obiekt funktora za coś, co jest irytująco trywialne.

BTW, myślę, że może wtf_error jest rozszerzeniem.

+0

Nie zapominaj, że zaśmiecasz przestrzeń nazw klasami funktora. –

+2

@Paul Nathan: Zostało to rozwiązane przez anonimowe przestrzenie nazw. –

+0

Roberts: dzięki za bardzo ładny przykład użycia Lamda. – Chan

0

Jak zauważyłeś, działa najlepiej, gdy potrzebujesz jednorazowej operacji, a narzut związany z kodowaniem zapisywania jej jako funkcji nie jest tego wart.

+0

dzięki za szybką odpowiedź. Ale nie rozumiem, jaka była motywacja do wymyślania 'lamda', ponieważ uważam, że trudniej ją odczytać i nie można jej użyć ponownie. Nie ma również nazwy, więc odczyt kodu wymaga znacznie więcej czasu. – Chan

+0

@Chan: Herb Sutter był jednym z najbardziej zagorzałych zwolenników lambd. Opowiedział o nich: http://herbsutter.com/2010/10/30/pdc-languages-panel-andshortened-lambdas-talk/. Nie obserwowałem ich osobiście, ale bez wątpienia powiedzą ci, do czego * on * sądzi, że są dla nich dobre, i podam przykłady, kiedy ich użyje. –

+0

@Steve Jessop: dzięki za link. Obejrzę to. – Chan

14

Wyrażenie lambda tworzy bezimienny funktor, to syntaktyczny cukier.

Używasz go głównie wtedy, gdy poprawia twój kod. Zdarza się to zazwyczaj, gdy (a) nie zamierzasz ponownie użyć funktora, lub (b) zamierzasz go ponownie użyć, ale z kodu tak całkowicie niezwiązanego z bieżącym kodem, że w celu jego udostępnienia zasadniczo w końcu tworzy się my_favourite_two_line_functors.h i zależą od niego różne pliki.

Niemal takie same warunki, w których można wpisać dowolną linię kodu, a nie abstrahować, że kod blokuje się w funkcję.

To powiedziawszy, w przypadku instrukcji range-for w C++ 0x, jest kilka miejsc, w których używałbyś funktora, zanim dobrze by teraz wyglądał, aby Twój kod wyglądał lepiej teraz, aby zapisać kod jako ciało pętli, a nie funktor lub lambda.

8

Niewielkie funkcje, które nie są powtarzane.

Głównym narzekaniem na funktory jest to, że nie znajdują się w tym samym miejscu, w którym zostały użyte. Musiałeś więc znaleźć i odczytać funktor z kontekstu do miejsca, w którym był on używany (nawet jeśli jest używany tylko w jednym miejscu).

Innym problemem było to, że funktor wymagał okablowania, aby uzyskać parametry obiektu funktora. Nie jest to skomplikowany, ale cały podstawowy kod na płycie głównej. Płyta kotła jest podatna na przecięcia i wklejenia.

Lambda wypróbuj i napraw oba. Ale użyłbym funktorów, jeśli funkcja jest powtarzana w wielu miejscach lub jest większa niż (nie można wymyślić odpowiedniego terminu, ponieważ będzie to kontekstowa) mała.

10

Lambdas to w zasadzie właśnie cukier syntaktyczny, który implementuje funktory (Uwaga: zamknięcia nie są proste.) W C++ 0x możesz użyć słowa kluczowego auto do lokalnego zapisywania lambdas, a funkcja std :: umożliwi zapisywanie lambdas lub przekazywanie ich w bezpieczny sposób.

Zapoznaj się z Wikipedia article on C++0x.

0

koncepcyjnym, którego decyzja w użyciu jest napędzany przez tego samego kryterium, jak za pomocą zmiennej o nazwie kontra wyrażenie lub stała w miejscu ...

size_t length = strlen(x) + sizeof(y) + z++ + strlen('\0'); 
... 
allocate(length); 
std::cout << length; 

. ..tutaj, tworzenie zmiennej długości zachęca program do rozważenia jego poprawności i znaczenia w oderwaniu od jego późniejszego użycia. Nazwa ma nadzieję, że przekazuje się na tyle, że można ją zrozumieć intuicyjnie i niezależnie od jej początkowej wartości. Następnie pozwala na użycie wartości kilkakrotnie bez powtarzania wyrażenia (przy jednoczesnym zachowaniu innej wartości). Podczas gdy tutaj ...

allocate(strlen(x) + sizeof(y) + z++ + strlen('\0')); 

... całkowity kod jest zmniejszany, a wartość jest zlokalizowana w miejscu, w którym jest potrzebna. Jedyną rzeczą do "przeniesienia naprzód" z odczytu tej linii są skutki uboczne przydziału i przyrostu (z), ale nie ma dodatkowej zmiennej lokalnej z zakresem lub późniejszym zastosowaniem do rozważenia. Programista musi mentalnie żonglować mniej stanu, kontynuując analizę kodu.

To samo rozróżnienie dotyczy instrukcji funkcji a instrukcji śródliniowych. Aby odpowiedzieć na twoje pytanie, funktory versus lambdy mogą być postrzegane tylko jako szczególny przypadek tej funkcji w stosunku do podejmowania decyzji.