L' +
espressione +[](){}
è l' +
operatore unario . È definito come segue in [expr.unary.op] / 7:
L'operando dell'operatore unario +
deve avere un'enumerazione aritmetica, senza ambito o un tipo di puntatore e il risultato è il valore dell'argomento.
La lambda non è di tipo aritmetico ecc., Ma può essere convertita:
[expr.prim.lambda] / 3
Il tipo di espressione lambda [...] è un tipo di classe non union univoco e senza nome, chiamato tipo di chiusura , le cui proprietà sono descritte di seguito.
[expr.prim.lambda] / 6
Il tipo di chiusura per una lambda espressione senza lambda-cattura ha una public
non virtual
non explicit
const
funzione di conversione di puntatore alla funzione avente gli stessi tipi di parametri e di ritorno come operatore chiamata di funzione del tipo di chiusura. Il valore restituito da questa funzione di conversione deve essere l'indirizzo di una funzione che, quando invocata, ha lo stesso effetto dell'invocazione dell'operatore di chiamata di funzione del tipo di chiusura.
Pertanto, l'unario +
forza la conversione al tipo di puntatore a funzione, che è per questo lambda void (*)()
. Pertanto, il tipo di espressione +[](){}
è questo tipo di puntatore a funzione void (*)()
.
Il secondo sovraccarico void foo(void (*f)())
diventa una corrispondenza esatta nella classifica per la risoluzione del sovraccarico e viene quindi scelto in modo univoco (poiché il primo sovraccarico NON è una corrispondenza esatta).
Il lambda [](){}
può essere convertito std::function<void()>
tramite il template ctor non esplicito di std::function
, che accetta qualsiasi tipo che soddisfi i requisiti Callable
e CopyConstructible
.
La lambda può anche essere convertita void (*)()
tramite la funzione di conversione del tipo di chiusura (vedi sopra).
Entrambe sono sequenze di conversione definite dall'utente e dello stesso rango. Ecco perché la risoluzione del sovraccarico non riesce nel primo esempio a causa dell'ambiguità.
Secondo Cassio Neri, supportato da un argomento di Daniel Krügler, questo +
trucco unario dovrebbe essere un comportamento specificato, cioè ci si può fidare (vedi discussione nei commenti).
Tuttavia, consiglierei di utilizzare un cast esplicito al tipo di puntatore a funzione se si desidera evitare l'ambiguità: non è necessario chiedere a SO cosa fa e perché funziona;)
std::bind
a unstd::function
oggetto che può essere chiamato in modo simile a una funzione lvalue.