Oui, le code est conforme aux normes. Le site +
déclenche une conversion en un bon vieux pointeur de fonction pour le lambda.
Voici ce qui se passe :
Le compilateur voit le premier lambda ( []{}
) et génère un objet de fermeture conformément au §5.1.2. Comme le lambda est un non-capture lambda, ce qui suit s'applique :
5.1.2 Les expressions lambda [expr.prim.lambda]
6 Le type de fermeture d'un expression lambda sans Capture lambda possède une fonction publique non virtuelle non explicite de conversion const vers un pointeur vers une fonction ayant les mêmes types de paramètres et de retour que l'opérateur d'appel de fonction du type de fermeture. La valeur renvoyée par cette fonction de conversion doit être l'adresse d'une fonction qui, lorsqu'elle est invoquée, a le même effet que l'invocation de l'opérateur d'appel de fonction du type de fermeture.
Ceci est important car l'opérateur unaire +
possède un ensemble de surcharges intégrées, notamment celle-ci :
13.6 Opérateurs incorporés [over.built].
8 Pour chaque type T
il existe des fonctions d'opérateur candidates de la forme
T* operator+(T*);
Et avec ça, ce qui se passe est assez clair : Quand l'opérateur +
est appliqué à l'objet de fermeture, l'ensemble des candidats intégrés surchargés contient une conversion vers un pointeur de fonction et le type de fermeture contient exactement un candidat : la conversion vers le pointeur de fonction de la lambda.
Le type de test
en auto test = +[]{};
est donc déduit de void(*)()
. Maintenant, la deuxième ligne est facile : pour le deuxième objet lambda/fermeture, une affectation au pointeur de fonction déclenche la même conversion que dans la première ligne. Même si le deuxième lambda a un type de fermeture différent, le pointeur de fonction résultant est, bien sûr, compatible et peut être assigné.