2011-01-13 13 views
31

Ich frage mich, wo sollten wir Lambda Ausdruck über Funktor in C++ verwenden. Für mich sind diese beiden Techniken im Grunde die gleichen, sogar Funktor ist eleganter und sauberer als Lambda. Zum Beispiel, wenn ich mein Prädikat wiederverwenden möchte, muss ich den Lambda-Teil immer wieder kopieren. Wann kommt Lambda wirklich an Ort und Stelle?Lambda-Ausdruck vs Functor in C++

+1

BTW, weiß nicht, dass ich "Lambda" als Code setzen würde. Es ist kein Schlüsselwort oder Typ in C++. Es gibt so etwas wie einen 'Lambda-Ausdruck', aber 'Lambda' ist nichts, was Sie im Code sehen würden, es sei denn, Sie verwenden die Lambda-Bibliothek von Boost oder hätten tatsächlich etwas, das in Ihrem eigenen Code heißt. –

+0

@Noah Roberts: Vielen Dank für das darauf hinweisen. Bearbeitet! Mein Punkt war, das Wort zu betonen. – Chan

Antwort

12

1) Es ist trivial und es zu teilen ist mehr Arbeit als Nutzen.

2) Definieren eines Funktors fügt einfach Komplexität hinzu (aufgrund der Notwendigkeit, eine Reihe von Elementvariablen und Mist zu erstellen).

Wenn keines dieser Dinge wahr ist, dann sollten Sie vielleicht darüber nachdenken, einen Funktor zu definieren.

Edit: Es scheint, dass Sie ein Beispiel brauchen, wenn es schön wäre, ein Lambda über einen Funktor zu verwenden. Hier gehen Sie:

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; 
} 

Ohne lambda würden Sie haben etwas zu verwenden, die in ähnlicher Weise einen Funktor auf der Stelle konstruiert oder schreiben Sie ein extern verknüpfbar Funktors Objekt für etwas, das annoyingly trivial ist.

BTW, ich denke, vielleicht wtf_error ist eine Erweiterung.

+0

Vergessen Sie nicht, dass Sie Ihren Namensraum mit Funktorklassen überladen. –

+2

@Paul Nathan: Das wurde durch anonyme Namespaces gelöst. –

+0

Roberts: Danke für ein sehr schönes Beispiel von Lamda. – Chan

0

Wie Sie gesagt haben, funktioniert es am besten, wenn Sie eine einmalige benötigen und der Programmieraufwand, es als eine Funktion zu schreiben, ist es nicht wert.

+0

danke für deine schnelle antwort. Aber ich verstehe nicht, was die Motivation war, 'Lamda' zu erfinden, da ich denke, dass es schwerer zu lesen ist und es nicht wiederverwendbar ist. Es hat auch keinen Namen, so dass das Lesen von Code viel mehr Zeit benötigt. – Chan

+0

@Chan: Herb Sutter war einer der lautesten Befürworter für Lambdas. Er schrieb einige Vorträge über sie: http://herbsutter.com/2010/10/30/pdc-languages-panel-andshortened-lambdas-talk/. Ich habe sie nicht selbst beobachtet, aber sie werden dir zweifellos sagen, was er für gut hält, und einige Beispiele geben, wann er sie benutzen würde. –

+0

@Steve Jessop: Danke für den Link. Ich werde es anschauen. – Chan

14

Ein Lambda-Ausdruck erzeugt einen namenlosen Funktor, es ist syntaktischer Zucker.

Sie verwenden es also hauptsächlich, wenn es Ihren Code besser aussehen lässt. Das würde im Allgemeinen passieren, wenn entweder (a) du den Funktor nicht wiederverwenden willst oder (b) du es wiederverwenden willst, aber aus Code, der so völlig nicht mit dem aktuellen Code zusammenhängt, um ihn zu teilen Am Ende erstellen my_favourite_two_line_functors.h, und verschiedene Dateien hängen davon ab.

So ziemlich die gleichen Bedingungen, unter denen Sie jede Codezeile eingeben würden und diesen Codeblock nicht in eine Funktion abstrahieren.

Das heißt, mit Range-for-Anweisungen in C++ 0x, gibt es einige Stellen, an denen Sie einen Funktor zuvor verwendet hätten, wo es Ihren Code jetzt besser aussehen lassen könnte, den Code als Schleifenkörper zu schreiben ein Funktor oder ein Lambda.

8

Kleine Funktionen, die nicht wiederholt werden.

Die wichtigste Beschwerde über Funktoren ist, dass sie nicht an der gleichen Stelle sind, an der sie verwendet wurden. Also mussten Sie den Funktor aus dem Zusammenhang mit dem Ort finden und lesen, an dem er verwendet wurde (auch wenn er nur an einer Stelle verwendet wird).

Das andere Problem war, dass Funktor einige Verdrahtung benötigt, um Parameter in das Funktor-Objekt zu bekommen. Nicht komplex, aber alle grundlegenden Vortex-Code. Und Kesselplatte ist anfällig für Probleme beim Schneiden und Einfügen.

Lambda versuchen und beide zu beheben. Aber ich würde functors verwenden, wenn die Funktion an mehreren Stellen wiederholt wird oder größer ist als ein kontextabhängiger Begriff (kann nicht passen).

10

Lambdas sind im Grunde nur syntaktische Zucker, die Funktoren implementieren (NB: Verschlüsse sind nicht einfach.) In C++ 0x können Sie das Schlüsselwort auto verwenden, um lambdas lokal zu speichern, und mit std :: function können Sie lambdas speichern oder typsicher übergeben.

Schauen Sie sich die Wikipedia article on C++0x.

0

Konzeptionell ist die Entscheidung, welche durch das gleiche Kriterium angetrieben zu verwenden, wie eine benannte Variable im Vergleich zu einem in-Place-Ausdruck oder Konstante mit ...

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

. ..hier, die Erstellung einer Längenvariable ermutigt das Programm, seine Korrektheit und Bedeutung zu betrachten, isoliert von seiner späteren Verwendung. Der Name vermittelt hoffentlich genug, dass er intuitiv und unabhängig von seinem Ausgangswert verstanden werden kann. Dann kann der Wert mehrere Male verwendet werden, ohne den Ausdruck zu wiederholen (während z anders gehandhabt wird). Während hier ...

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

... wird der Gesamtcode reduziert und der Wert wird an der Stelle lokalisiert, an der er benötigt wird. Die einzige Sache, die aus einem Lesen dieser Zeile "weitergeführt" werden kann, sind die Nebenwirkungen von Zuweisung und Inkrement (z), aber es gibt keine zusätzliche lokale Variable mit Gültigkeitsbereich oder späterer Verwendung. Der Programmierer muss mental mit weniger Staat jonglieren, während er die Analyse des Codes fortsetzt.

Die gleiche Unterscheidung gilt für Funktionen versus Inline-Anweisungen. Zur Beantwortung Ihrer Frage können Funktoren gegenüber Lambdas nur als ein spezieller Fall dieser Funktion gegenüber der Entscheidungsfindung gesehen werden.