Es gibt ein paar Dinge in Bezug auf Ihre Frage zu klären. Der erste ist Was ist ein Lambda?
Ein Lambda-Ausdruck ist ein einfacher Ausdruck, aus dem der Compiler einen eindeutigen Typ generiert, der nicht benannt werden kann, und gleichzeitig wird eine Instanz des Typs generiert. Wenn Sie schreiben: [](int i) { std::cout << i; }
der Compiler generiert für Sie ein Typ, der grob ist:
struct __lambda_unique_name {
void operator()(int i) const { std::cout << i; }
};
Wie Sie sehen können, ist es nicht eine Funktion ist, aber ein Typ, der operator()
als const
Member-Funktion implementiert. Wenn das Lambda irgendeine Erfassung durchgeführt hat, würde der Compiler Code erzeugen, um den Wert/die Referenzen zu erfassen.
als Ecke Fall für Lambdas wie die oben, wo es kein Zustand ist, erfaßt wird, ermöglicht die Sprache für eine Umwandlung von dem Lambda-Typ auf einen Zeiger mit der Signatur der operator()
(minus den this
Teil) funktionieren , so über das Lambda implizit in einen Zeiger umgewandelt werden kann funktionieren int
nehmen und Rückkehr nichts:
void (*f)(int) = [](int i) { std::cout << i; }
Jetzt, wo die Grundlagen in Ihrem Code angegeben, wurden, haben Sie das Lambda:
auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};
Die Regeln für Parameter zu Funktionen (die auch für Lambdas gelten) legen fest, dass ein Argument nicht vom Typ Funktion sein kann, so dass das Argument zum Lambda zu einem Zeiger auf Funktion abfällt (in gleicher Weise wie ein Argument vom Typ Array Typ zerfällt in einen Zeiger):
auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};
zu einem späteren Zeitpunkt Sie eine Lambda passieren versuchen, die eine Erfassung als Argument hat. Da es ein Capture gibt, gilt die spezielle Regel nicht, und das Lambda kann nicht in einen Zeiger umgewandelt werden, der den Compilerfehler anzeigt, den Sie sehen.
Im aktuellen Standard können Sie einen von zwei Wegen gehen. Sie können Typ-Löschung verwenden, um die genaue Art der aufrufbaren Entität aus der Signatur zu entfernen:
auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};
Da ein std::function<double(int)>
mit jeder aufrufbar Einheit mit der entsprechenden Signatur initialisiert werden kann, das wird den Lambda-Ausdrücke in der nehmen Code auf Kosten der Typ-Löschung, die normalerweise eine dynamische Zuordnung und dynamischen Versand impliziert.
Alternativ können Sie den syntaktischen Zucker löschen und das erste Lambda-Äquivalent manuell, aber generisch machen. In diesem Fall, wo das Lambda einfach ist dies könnte eine gültige Option sein:
struct mylambda {
template <typename F>
double operator()(F fn) const {
fn(0); return 0.0;
}
} f;
// then use the non-lambda as you tried:
f([x](int i) -> double {return 0.0;});
Schließlich, wenn Sie geduldig genug sind, können Sie warten ++ 14 C, wobei (höchstwahrscheinlich hat es noch nicht gewesen ratifiziert) wird es Unterstützung für polymorph lambdas sein, die die Schaffung der oben genannten Klasse vereinfachen:
auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above
Capturing Lambdas sind nicht konvertierbar, um Zeiger zu funktionieren –
warum nicht ein 'constexpr'? 'auto' ist sowieso eine Kompilierfunktion ... – user2485710
@AndyProwl Was? Keine detaillierte Antwort von Ihnen innerhalb von 10 Minuten? Komm, du lässt uns hier zu hart arbeiten, und du hast nicht mal für den Tag reappt ;-) – TemplateRex