L' +
dans l'expression +[](){}
est unaire +
de l'opérateur. Il est défini comme suit dans
[expr.unaire.op]/7:
L'opérande de l'unaire +
opérateur aura l'arithmétique, non délimité énumération, ou de type pointeur et le résultat est la valeur de l'argument.
Le lambda n'est pas de l'arithmétique type etc., mais il peut être converti:
[expr.prim.lambda]/3
Le type de la lambda-expression [...] est un unique, sans nom non-union type de classe qu'on appelle la fermeture type - dont les propriétés sont décrites ci-dessous.
[expr.prim.lambda]/6
La fermeture pour un type lambda-expression avec pas de lambda-capture a un public
nonvirtual
nonexplicit
const
fonction de conversion de pointeur de fonction ayant le même paramètre et les types de retour de la fermeture du type de la fonction d'appel de l'opérateur. La valeur retournée par cette fonction de conversion doit être l'adresse d'une fonction qui, lorsqu'il est appelé, a le même effet que l'invocation de la fermeture du type de la fonction d'appel de l'opérateur.
Par conséquent, le unaire +
des forces de la conversion à la fonction de type pointeur, qui est pour cette lambda void (*)()
. Par conséquent, le type de l'expression +[](){}
est-ce la fonction de type de pointeur void (*)()
.
La seconde surcharge void foo(void (*f)())
devient une Correspondance Exacte dans le classement pour la résolution de surcharge et est donc choisis sans ambiguïté (comme la première surcharge n'est PAS une Correspondance Exacte).
Le lambda [](){}
peut être converti std::function<void()>
via le non-explicite modèle ctor d' std::function
, qui prend n'importe quel type qui remplit l' Callable
et CopyConstructible
exigences.
Le lambda peut également être converti en void (*)()
via la fonction de conversion de la fermeture type (voir ci-dessus).
Les deux sont définis par l'utilisateur de conversion de séquences, et de même rang. C'est pourquoi la résolution de surcharge d'échec dans le premier exemple en raison de l'ambiguïté.
Selon Cassio Neri, soutenue par un argument par Daniel Krügler, ce unaire +
astuce doit être spécifiée comportement, c'est à dire que vous pouvez compter sur elle (voir la discussion dans les commentaires).
Encore, je vous recommande d'utiliser un cast explicite pour la fonction type de pointeur, si vous voulez éviter l'ambiguïté: vous n'avez pas besoin de demander SI ce qui est fait et pourquoi il fonctionne ;)