Quel est le type de lambda lorsqu’il est déduit avec «auto» en C ++ 11?

J’ai eu l’impression que le type d’un lambda est un pointeur de fonction. Lorsque j’ai effectué le test suivant, je l’ai trouvé faux ( démo ).

#define LAMBDA [] (int i) -> long { return 0; } int main () { long (*pFptr)(int) = LAMBDA; // ok auto pAuto = LAMBDA; // ok assert(typeid(pFptr) == typeid(pAuto)); // assertion fails ! } 

Le code ci-dessus manque-t-il un point? Sinon, quel est le typeof une expression lambda déduite avec auto mot-clé auto ?

Le type d’une expression lambda n’est pas spécifié.

Mais ils ne sont généralement que du sucre syntaxique pour les foncteurs. Un lambda est traduit directement dans un foncteur. Tout ce qui se trouve à l’intérieur de [] est transformé en parameters de constructeur et en membres de l’object fonctor, et les parameters contenus dans () sont transformés en parameters pour l’ operator() du foncteur.

Un lambda qui ne capture aucune variable (rien dans le [] ne peut être converti en un pointeur de fonction (MSVC2010 ne le supporte pas, si tel est votre compilateur, mais cette conversion fait partie du standard).

Mais le type réel du lambda n’est pas un pointeur de fonction. C’est un type de foncteur non spécifié.

C’est une structure unique non nommée qui surcharge l’opérateur d’appel de fonction. Chaque instance d’un lambda introduit un nouveau type.

Dans le cas particulier d’un lambda non capturant, la structure a en outre une conversion implicite en un pointeur de fonction.

[C++11: 5.1.2/3]: Le type de l’ expression lambda (qui est également le type de l’object de fermeture) est un type de classe non-union unique, sans nom – appelé type de fermeture – dont les propriétés sont décrit ci-dessous. Ce type de classe n’est pas un agrégat (8.5.1). Le type de fermeture est déclaré dans la plus petite étendue de bloc, la scope de classe ou la scope d’espace de noms qui contient l’ expression lambda correspondante. [..]

La clause continue à lister les propriétés de ce type. Voici quelques points saillants:

[C++11: 5.1.2/5]: Le type de fermeture d’une expression lambda a un opérateur d’appel de fonction public en inline (13.5.4) dont les parameters et le type de retour sont décrits par la déclaration de paramètre de l’ expression lambda -clause et trailing-return-type respectivement. [..]

[C++11: 5.1.2/6]: le type de fermeture d’une expression lambda sans capture de lambda a une fonction de conversion const non virtuelle et non explicite à un pointeur vers une fonction ayant le même paramètre et les mêmes types de retour que l’opérateur d’appel de la 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’appel de l’opérateur d’appel de fonction du type de fermeture.

La conséquence de ce dernier passage est que, si vous pFptr une conversion, vous seriez en mesure d’atsortingbuer LAMBDA à pFptr .

 #include  #include  #define LAMBDA [] (int i)->long { return 0l; } int main () { long (*pFptr)(int) = LAMBDA; // ok auto pAuto = LAMBDA; // ok std::cout< 

Les types de fonctions sont en effet les mêmes, mais le lambda introduit un nouveau type (comme un foncteur).

Une solution pratique de Comment puis-je stocker un object boost :: bind en tant que membre de la classe? , essayez boost::function ou std::function .

Il convient également de noter que lambda est convertible en pointeur de fonction. Cependant, typeid <> renvoie un objet non-trvial qui doit différer de lambda à un pointeur de fonction générique. Le test de typeid <> n’est donc pas une hypothèse valide. En général, C ++ 11 ne veut pas que nous nous préoccupions de la spécification de type, tout ce qui importe si un type donné est convertible en un type cible.