web-dev-qa-db-fra.com

Fonction renvoyant une expression lambda

Je me demande s'il est possible d'écrire une fonction qui retourne une fonction lambda en C++ 11. Bien sûr, un problème est de savoir comment déclarer une telle fonction. Chaque lambda a un type, mais ce type n'est pas exprimable en C++. Je ne pense pas que cela fonctionnerait:

auto retFun() -> decltype ([](int x) -> int)
{
    return [](int x) { return x; }
}

Ni ça:

int(int) retFun();

Je ne suis pas au courant de conversions automatiques de lambdas vers, par exemple, des pointeurs vers des fonctions, ou quelque chose du genre. La seule solution est-elle de fabriquer à la main un objet fonction et de le renvoyer?

83
Bartosz Milewski

Vous n'avez pas besoin d'un objet fonction artisanal, utilisez simplement std::function, dans lequel les fonctions lambda sont convertibles:

Cet exemple renvoie la fonction d'identité entière:

std::function<int (int)> retFun() {
    return [](int x) { return x; };
}
93
Sean

Pour cet exemple simple, vous n'avez pas besoin de std::function.

De la norme §5.1.2/6:

Le type de fermeture pour un expression-lambda sans capture-lambda a une fonction de conversion de const publique non virtuelle non explicite pour pointer vers la fonction ayant le même paramètre et les mêmes types de retour comme 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.

Parce que votre fonction n'a pas de capture, cela signifie que le lambda peut être converti en un pointeur en fonction de type int (*)(int):

typedef int (*identity_t)(int); // works with gcc
identity_t retFun() { 
  return [](int x) { return x; };
}

C'est ma compréhension, corrigez-moi si je me trompe.

29
user534498

Vous pouvez renvoyer la fonction lambda à partir d'une autre fonction lambda, car vous ne devez pas spécifier explicitement le type de retour de la fonction lambda. Écrivez simplement quelque chose comme ça dans une portée globale:

 auto retFun = []() {
     return [](int x) {return x;};
 };
20
dzhioev

Bien que la question concerne spécifiquement C++ 11, pour le bien des autres qui trébuchent dessus et ont accès à un compilateur C++ 14, C++ 14 autorise désormais les types de retour déduits pour les fonctions ordinaires. Ainsi, l'exemple de la question peut être ajusté pour fonctionner comme vous le souhaitez simplement en supprimant la clause -> decltype ... après la liste des paramètres de fonction:

auto retFun()
{
    return [](int x) { return x; }
}

Notez cependant que cela ne fonctionnera pas si plusieurs return <lambda>; Apparaissent dans la fonction. En effet, une restriction sur la déduction du type de retour est que toutes les instructions de retour doivent renvoyer des expressions du même type, mais chaque objet lambda reçoit son propre type unique par le compilateur, de sorte que les expressions return <lambda>; Auront chacune une expression différente type.

15
Anthony Hall

Vous devez écrire comme ceci:

auto returnFunction = [](int x){
    return [&x](){
        return x;
    }();
};

pour obtenir votre retour en tant que fonction, et l'utiliser comme:

int val = returnFunction(someNumber);
0
Terens Tare