2012-06-12 19 views
8

Ich fange an, Anwendungen zu entwickeln, die C++ 11 Lambdas verwenden, und einige Typen in Funktionszeiger konvertieren müssen. Das funktioniert perfekt in GCC 4.6.0:C++ 11 Lambdas zu Funktionszeiger

void (* test)() = []() 
{ 
    puts("Test!"); 
}; 

test(); 

Mein Problem ist, wenn ich brauche, um Funktion oder Methode lokale Variablen innerhalb der Lambda zu verwenden: Code

const char * text = "test!"; 

void (* test)() = [&]() 
{ 
    puts(text); 
}; 

test(); 

G ++ 4.6.0 gibt dem Gussfehler:

main.cpp: In function 'void init(int)': 
main.cpp:10:2: error: cannot convert 'main(int argc, char ** argv)::<lambda()>' to 'void (*)()' in initialization 

Wenn Verwendung Auto, es funktioniert ok:

const char * text = "Test!"; 

auto test = [&]() 
{ 
    puts(text); 
}; 

test(); 

Meine Frage ist: Wie kann ich einen Typ für ein Lambda mit [&] erstellen? In meinem Fall kann ich nicht die STL Std :: Funktion (weil mein Programm nicht C++ RTTI und EXCEPTIONS Laufzeit verwendet), und es hat eine einfache Implementierung von Funktion, um dieses Problem zu lösen?

+8

Klingt wie eine Instanz des [XY-Problems] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). –

+3

Sie können ein erfassendes Lambda nicht in einen Funktionszeiger konvertieren. Erkläre, was du zu tun versuchst. –

+0

Sie haben eine (versuchte) Lösung erklärt, obwohl Sie nicht beschreiben, was Ihr Problem ist. Bitte sagen Sie uns, was Sie eigentlich Problem ist – thecoshman

Antwort

8

ich nicht die STL std :: Funktion nutzen zu können (weil mein Programm nicht C++ verwenden RTTI und Ausnahmen Laufzeit)

Dann müssen Sie möglicherweise Ihre eigene Entsprechung zu std::function schreiben.

Die übliche Implementierung von Typ löschen für std::function benötigt RTTI für die meisten seiner Funktionalität nicht; Es funktioniert durch regelmäßige virtuelle Funktionsaufrufe. So ist es möglich, eine eigene Version zu schreiben.

der Tat das einzige, was in std::function dass brauchen RTTI sind die target_type und target Funktionen, die in der Welt nicht die nützlichsten Funktionen sind. Sie können möglicherweise std::function verwenden, ohne diese Funktionen aufzurufen, vorausgesetzt, dass die von Ihnen verwendete Implementierung RTTI für ihre üblichen Aufgaben nicht benötigt.

Wenn Sie die Ausnahmebehandlung deaktivieren, wird das Programm normalerweise heruntergefahren und es treten Fehler auf, wenn eine throw-Anweisung auftritt.Und da die meisten Ausnahmen, die ein std::function aussenden würde, nicht die Art von Sache sind, von der Sie wiederherstellen könnten (eine leere function aufrufen, nicht genügend Arbeitsspeicher usw.), können Sie wahrscheinlich einfach std::function verwenden, wie es ist.

8

Nur Lambdas ohne Capture können in einen Funktionszeiger konvertiert werden. Dies ist eine Erweiterung von Lambdas nur für diesen speziellen Fall [*]. Im Allgemeinen sind Lambdas Funktionsobjekte, und Sie können ein Funktionsobjekt nicht in eine Funktion konvertieren.

Die Alternative für Lambdas mit Status (Capture) ist die Verwendung von std::function statt eines einfachen Funktionszeigers.


[*]: Wenn das Lambda, den Staat hält umgewandelt werden könnte Zeiger auf Funktion, wo würde der Zustand gehalten? (Beachten Sie, dass es möglicherweise mehrere Instanzen dieses speziellen Lambda sein, von denen jeder mit einem eigenen Staat, separat gehalten werden muss)

+0

Nun, wenn Sie es wie folgt übergeben: const int c; [c] (int i) -> int {return i * c;} 'es würde sehr viel Sinn machen ... –

+0

@BarnabasSzabolcs: Es kommt darauf an,' std :: function f (int x) {const int c = x; zurückgeben [c] (int i) {zurück i * c;}}; '. Der mit 'f' zurückgegebene Funktor hängt von seinem Argument ab und hat daher einen Zustand. Nur wenn das Capture ein konstanter Ausdruck wäre, könnte es in eine einfache Funktion einbezogen werden. –

+0

Hm. Ich stimme teilweise zu. Es kann immer noch abgezogen werden, aber die Lösung kann teuer sein, da das Programm den Code der Lambda-Funktion jedes Mal kopieren muss, wenn der Wert von c im Funktionscode geändert wird. (oder wenn nicht der gesamte Code der Funktion kopiert wird, muss es geplante Sprünge machen, wobei die Sprünge die Dinge verlangsamen können.) –

6

Wie bereits erwähnt, können nur Lambdas, die nichts erfassen, in Funktionszeiger umgewandelt werden.

Wenn Sie nicht etwas wie std :: function verwenden oder schreiben wollen, dann besteht eine andere Alternative darin, als Parameter die Dinge zu übergeben, die Sie sonst erfassen würden. Sie können sogar eine Struktur erstellen, um sie zu speichern.

#include <iostream> 

struct captures { int x; }; 
int (*func)(captures *c) = [](captures *c){ return c->x; }; 

int main() { 
    captures c = {10}; 

    std::cout << func(&c) << '\n'; 
} 

Eine weitere Alternative ist global/statisch/thread_local/constexpr Variablen zu verwenden, die die Erfassung nicht benötigen.