W +
wyrażeniu +[](){}
jest +
operatorem jednoargumentowym . W [expr.unary.op] / 7 jest zdefiniowany w następujący sposób:
Operand +
operatora jednoargumentowego powinien mieć typ arytmetyczny, wyliczeniowy bez zakresu lub typ wskaźnika, a wynikiem jest wartość argumentu.
Lambda nie jest typu arytmetycznego itp., Ale można ją przekonwertować:
[wyr.prim.lambda] / 3
Typ wyrażenia lambda [...] jest unikalnym, nienazwanym typem klasy nieunijnej - zwanym typem zamknięcia - którego właściwości opisano poniżej.
[wyr.prim.lambda] / 6
Typ zamknięcia do lambda ekspresji bez lambda chwytania ma public
Nieskarbowych virtual
Nieskarbowych explicit
const
funkcję konwersji do wskaźnika do funkcji o tych samych typów parametrów i powrotnym dla obsługi funkcji danego typu Zamknięcie-tych. Wartość zwracana przez tę funkcję konwersji będzie adresem funkcji, która po wywołaniu ma taki sam skutek, jak wywołanie operatora wywołania funkcji typu zamknięcia.
Dlatego jednoargumentowa +
wymusza konwersję do typu wskaźnika funkcji, który jest dla tej lambdy void (*)()
. Dlatego typ wyrażenia +[](){}
to ten typ wskaźnika funkcji void (*)()
.
Drugie przeciążenie void foo(void (*f)())
staje się dokładnym dopasowaniem w rankingu rozpoznawania przeciążenia i w związku z tym jest wybierane jednoznacznie (ponieważ pierwsze przeciążenie NIE jest dokładnym dopasowaniem).
Lambda [](){}
można przekonwertować na std::function<void()>
za pomocą niejawnego edytora szablonu programu std::function
, który przyjmuje dowolny typ, który spełnia wymagania Callable
i CopyConstructible
.
Lambda można również przekonwertować na void (*)()
funkcję konwersji typu zamknięcia (patrz wyżej).
Obie są sekwencjami konwersji zdefiniowanymi przez użytkownika i mają tę samą rangę. Dlatego rozpoznawanie przeciążenia w pierwszym przykładzie zawodzi z powodu niejednoznaczności.
Zdaniem Cassio Neri, popartego argumentem Daniela Krüglera, ta jednoargumentowa +
sztuczka powinna być określonym zachowaniem, tj. Można na nim polegać (patrz dyskusja w komentarzach).
Mimo to polecam użycie jawnego rzutowania na typ wskaźnika funkcji, jeśli chcesz uniknąć niejednoznaczności: nie musisz pytać SO, co się dzieje i dlaczego działa;)
std::bind
zstd::function
obiektem, który można wywołać podobnie do funkcji lwartość.