Ich habe mit C ++ Lambdas und deren impliziter Konvertierung in Funktionszeiger gespielt. Mein Startbeispiel war, sie als Rückruf für die ftw-Funktion zu verwenden. Dies funktioniert wie erwartet.
#include <ftw.h>
#include <iostream>
using namespace std;
int main()
{
auto callback = [](const char *fpath, const struct stat *sb,
int typeflag) -> int {
cout << fpath << endl;
return 0;
};
int ret = ftw("/etc", callback, 1);
return ret;
}
Nach dem Ändern, um Captures zu verwenden:
int main()
{
vector<string> entries;
auto callback = [&](const char *fpath, const struct stat *sb,
int typeflag) -> int {
entries.push_back(fpath);
return 0;
};
int ret = ftw("/etc", callback, 1);
for (auto entry : entries ) {
cout << entry << endl;
}
return ret;
}
Ich habe den Compilerfehler erhalten:
error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’
Nach einigem Lesen. Ich habe gelernt, dass Lambdas, die Captures verwenden, nicht implizit in Funktionszeiger konvertiert werden können.
Gibt es eine Problemumgehung dafür? Bedeutet die Tatsache, dass sie nicht "implizit" konvertiert werden können, dass sie "explizit" konvertiert werden können? (Ich habe versucht zu gießen, ohne Erfolg). Was wäre eine saubere Möglichkeit, das Arbeitsbeispiel so zu ändern, dass ich die Einträge mit Lambdas an ein Objekt anhängen kann?
c++
lambda
function-pointers
c++11
Duncan
quelle
quelle
void *
). Wenn die von Ihnen verwendete Bibliothek dieses zusätzliche Argument zulässt, finden Sie eine Problemumgehung. Andernfalls haben Sie keine Möglichkeit, sauber zu erreichen, was Sie tun möchten.Antworten:
Da das Erfassen von Lambdas einen Zustand bewahren muss, gibt es keine wirklich einfache "Problemumgehung", da es sich nicht nur um gewöhnliche Funktionen handelt. Der Punkt bei einem Funktionszeiger ist, dass er auf eine einzelne globale Funktion verweist und diese Informationen keinen Platz für einen Status haben.
Die nächstgelegene Problemumgehung (die im Wesentlichen die Statefulness verwirft) besteht darin, eine Art globale Variable bereitzustellen, auf die von Ihrem Lambda / Ihrer Funktion aus zugegriffen wird. Sie können beispielsweise ein traditionelles Funktorobjekt erstellen und ihm eine statische Elementfunktion zuweisen, die auf eine eindeutige (globale / statische) Instanz verweist.
Aber das ist eine Art Niederlage gegen den gesamten Zweck, Lambdas zu fangen.
quelle
namespace
und markiert sie alsthread_local
, das ist derftw
Ansatz, den ich gewählt habe, um etwas Ähnliches zu lösen.Ich bin gerade auf dieses Problem gestoßen.
Der Code wird ohne Lambda-Erfassung problemlos kompiliert, bei der Lambda-Erfassung tritt jedoch ein Typkonvertierungsfehler auf.
Die Lösung mit C ++ 11 ist die Verwendung
std::function
(Bearbeiten: Eine andere Lösung, bei der die Funktionssignatur nicht geändert werden muss, wird nach diesem Beispiel angezeigt). Sie können auch verwendenboost::function
(was tatsächlich deutlich schneller läuft). Beispielcode - geändert, damit er kompiliert wird, kompiliert mitgcc 4.7.1
:Bearbeiten: Ich musste dies erneut überprüfen, als ich auf alten Code stieß, bei dem ich die ursprüngliche Funktionssignatur nicht ändern konnte, aber dennoch Lambdas verwenden musste. Im Folgenden finden Sie eine Lösung, bei der die Funktionssignatur der ursprünglichen Funktion nicht geändert werden muss:
quelle
ftw
, umstd::function
anstelle eines Funktionszeigers zu nehmen ...ftw
ich ein void * userdata-Argument hätte, würde ich die Antwort von @ evgeny-karpov vorziehen.ORIGINAL
Lambda-Funktionen sind sehr praktisch und reduzieren einen Code. In meinem Fall brauchte ich Lambdas für die parallele Programmierung. Es erfordert jedoch Erfassungs- und Funktionszeiger. Meine Lösung ist hier. Seien Sie jedoch vorsichtig mit dem Umfang der Variablen, die Sie erfasst haben.
Beispiel
Beispiel mit einem Rückgabewert
AKTUALISIEREN
Verbesserte Version
Es ist eine Weile her, dass der erste Beitrag über C ++ Lambda mit Captures als Funktionszeiger veröffentlicht wurde. Da es für mich und andere Leute brauchbar war, habe ich einige Verbesserungen vorgenommen.
Die C-Zeiger-API der Standardfunktion verwendet die Konvention void fn (void * data). Standardmäßig wird diese Konvention verwendet und Lambda sollte mit einem void * -Argument deklariert werden.
Verbesserte Implementierung
Beispiel
Konvertieren von Lambda mit Captures in einen C-Zeiger
Kann auch so verwendet werden
Falls der Rückgabewert verwendet werden sollte
Und falls Daten verwendet werden
quelle
Mit der lokal globalen (statischen) Methode kann wie folgt vorgegangen werden
Angenommen, wir haben
So wird die Nutzung sein
Dies funktioniert, weil jedes Lambda eine eindeutige Signatur hat, sodass es kein Problem ist, es statisch zu machen. Es folgt ein generischer Wrapper mit einer variablen Anzahl von Argumenten und einem beliebigen Rückgabetyp, der dieselbe Methode verwendet.
Und ähnliche Verwendung
quelle
=
Verwendung&i
in der for-Schleife.Hehe - eine ziemlich alte Frage, aber immer noch ...
quelle
Es gibt eine hackige Möglichkeit, ein Erfassungs-Lambda in einen Funktionszeiger umzuwandeln, aber Sie müssen vorsichtig sein, wenn Sie es verwenden:
/codereview/79612/c-ifying-a-capturing-lambda
Ihr Code würde dann so aussehen (Warnung: Gehirn kompilieren):
quelle
Meine Lösung, verwenden Sie einfach einen Funktionszeiger, um auf ein statisches Lambda zu verweisen.
quelle
Hier finden Sie eine Antwort: http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
Er wandelt
lambda pointer
aufvoid*
und zurück konvertieren , wenn nötig.zu
void*
:Auto Voidfunction = neuer Dekltyp (to_function (Lambda)) (to_function (Lambda));
von
void*
:auto function = static_cast <std :: function *> (voidfunction);
quelle