Das +
im Ausdruck +[](){}
ist der unäre +
Operator. Es ist wie folgt in [expr.unary.op] / 7 definiert:
Der Operand des unären +
Operators muss eine arithmetische, nicht skalierte Aufzählung oder einen Zeigertyp haben, und das Ergebnis ist der Wert des Arguments.
Das Lambda ist nicht vom arithmetischen Typ usw., kann aber konvertiert werden:
[expr.prim.lambda] / 3
Der Typ des Lambda-Ausdrucks [...] ist ein eindeutiger, unbenannter Nicht-Union-Klassentyp - der so genannte Closure-Typ - dessen Eigenschaften im Folgenden beschrieben werden.
[expr.prim.lambda] / 6
Der Schließungstyp für einen Lambda-Ausdruck ohne Lambda-Erfassung verfügt über eine public
Nicht- virtual
Nicht- explicit
const
Konvertierungsfunktion zum Zeiger auf eine Funktion mit denselben Parameter- und Rückgabetypen wie der Funktionsaufrufoperator des Schließungstyps. Der von dieser Konvertierungsfunktion zurückgegebene Wert ist die Adresse einer Funktion, die beim Aufrufen den gleichen Effekt hat wie das Aufrufen des Funktionsaufrufoperators des Schließungstyps.
Daher +
erzwingt der Unäre die Konvertierung in den Funktionszeigertyp, der für dieses Lambda gilt void (*)()
. Daher ist der Typ des Ausdrucks +[](){}
dieser Funktionszeigertyp void (*)()
.
Die zweite Überladung void foo(void (*f)())
wird zu einer exakten Übereinstimmung in der Rangfolge für die Überlastungsauflösung und wird daher eindeutig ausgewählt (da die erste Überladung KEINE genaue Übereinstimmung ist).
Die Lambda [](){}
kann umgewandelt werden std::function<void()>
über die nicht explizit Vorlage Ctor von std::function
, die jede Art nimmt , die die erfüllt Callable
und CopyConstructible
Anforderungen.
Das Lambda kann auch void (*)()
über die Konvertierungsfunktion des Verschlusstyps umgerechnet werden (siehe oben).
Beide sind benutzerdefinierte Konvertierungssequenzen und haben denselben Rang. Aus diesem Grund schlägt die Überlastungsauflösung im ersten Beispiel aufgrund von Mehrdeutigkeiten fehl .
Laut Cassio Neri, unterstützt durch ein Argument von Daniel Krügler, sollte dieser unäre +
Trick ein bestimmtes Verhalten sein, dh Sie können sich darauf verlassen (siehe Diskussion in den Kommentaren).
Trotzdem würde ich empfehlen, eine explizite Umwandlung in den Funktionszeigertyp zu verwenden, wenn Sie die Mehrdeutigkeit vermeiden möchten: Sie müssen SO nicht fragen, was funktioniert und warum es funktioniert;)
std::bind
an einstd::function
Objekt binden , das ähnlich wie ein Funktionswert aufgerufen werden kann.