Je jouais avec les lambdas C ++ et leur conversion implicite en pointeurs de fonction. Mon exemple de départ les utilisait comme rappel pour la fonction ftw. Cela fonctionne comme prévu.
#include <ftw.h>
#include <iostream>
using namespace std;
int main()
{
auto callback = [](const char *fpath, const struct stat *sb,
int typeflag) -> int {
cout << fpath << endl;
return 0;
};
int ret = ftw("/etc", callback, 1);
return ret;
}
Après l'avoir modifié pour utiliser les captures:
int main()
{
vector<string> entries;
auto callback = [&](const char *fpath, const struct stat *sb,
int typeflag) -> int {
entries.push_back(fpath);
return 0;
};
int ret = ftw("/etc", callback, 1);
for (auto entry : entries ) {
cout << entry << endl;
}
return ret;
}
J'ai eu l'erreur du compilateur:
error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’
Après quelques lectures. J'ai appris que les lambdas utilisant des captures ne peuvent pas être implicitement convertis en pointeurs de fonction.
Existe-t-il une solution de contournement pour cela? Le fait qu'ils ne peuvent pas être convertis «implicitement» signifie-t-il qu'ils peuvent être convertis «explicitement»? (J'ai essayé le casting, sans succès). Quelle serait une manière propre de modifier l'exemple de travail afin que je puisse ajouter les entrées à un objet à l'aide de lambdas?.
la source
void *
). Si la bibliothèque que vous utilisez permet cet argument supplémentaire, vous trouverez une solution de contournement. Sinon, vous n'avez aucun moyen de réaliser proprement ce que vous voulez faire.Réponses:
Puisque la capture de lambdas doit préserver un état, il n'y a pas vraiment de "contournement" simple, car ce ne sont pas que des fonctions ordinaires. Le point sur un pointeur de fonction est qu'il pointe vers une seule fonction globale et que cette information n'a pas de place pour un état.
La solution de contournement la plus proche (qui supprime essentiellement l'état) est de fournir un type de variable globale accessible à partir de votre fonction / lambda. Par exemple, vous pouvez créer un objet foncteur traditionnel et lui donner une fonction membre statique qui fait référence à une instance unique (globale / statique).
Mais cela va en quelque sorte à l'encontre de l'objectif de capturer des lambdas.
la source
namespace
et les marque commethread_local
, c'est l'ftw
approche que j'ai choisie pour résoudre quelque chose de similaire.Je viens de rencontrer ce problème.
Le code se compile correctement sans capture lambda, mais il y a une erreur de conversion de type avec la capture lambda.
La solution avec C ++ 11 est d'utiliser
std::function
(modifier: une autre solution qui ne nécessite pas de modifier la signature de la fonction est affichée après cet exemple). Vous pouvez également utiliserboost::function
(qui fonctionne en fait beaucoup plus rapidement). Exemple de code - modifié pour qu'il compile, compilé avecgcc 4.7.1
:Edit: J'ai dû revoir cela lorsque je suis tombé sur du code hérité où je ne pouvais pas modifier la signature de la fonction d'origine, mais j'avais toujours besoin d'utiliser des lambdas. Une solution qui ne nécessite pas de modifier la signature de fonction de la fonction d'origine est ci-dessous:
la source
ftw
pour prendrestd::function
au lieu d'un pointeur de fonction ...ftw
j'avais un argument void * userdata, alors je préférerais la réponse de @ evgeny-karpov.ORIGINAL
Les fonctions Lambda sont très pratiques et réduisent un code. Dans mon cas, j'avais besoin de lambdas pour la programmation parallèle. Mais cela nécessite des pointeurs de capture et de fonction. Ma solution est ici. Mais soyez prudent avec la portée des variables que vous avez capturées.
Exemple
Exemple avec une valeur de retour
METTRE À JOUR
Version améliorée
Cela faisait un moment que le premier article sur C ++ lambda avec des captures comme pointeur de fonction avait été publié. Comme il était utilisable pour moi et pour d'autres personnes, j'ai apporté des améliorations.
La fonction standard API du pointeur C utilise la convention void fn (void * data). Par défaut, cette convention est utilisée et lambda doit être déclaré avec un argument void *.
Mise en œuvre améliorée
Exemple
Conversion de lambda avec des captures en un pointeur C
Peut également être utilisé de cette façon
Au cas où la valeur de retour devrait être utilisée
Et dans le cas où des données sont utilisées
la source
En utilisant la méthode locale globale (statique), cela peut être fait comme suit
Supposons que nous ayons
Donc, l'utilisation sera
Cela fonctionne car chaque lambda a une signature unique, donc le rendre statique n'est pas un problème. Voici un wrapper générique avec un nombre variable d'arguments et tout type de retour utilisant la même méthode.
Et usage similaire
la source
=
utiliser&i
dans votre boucle for.Hehe - une question assez ancienne, mais quand même ...
la source
Il existe un moyen malveillant de convertir un lambda de capture en un pointeur de fonction, mais vous devez être prudent lorsque vous l'utilisez:
/codereview/79612/c-ifying-a-capturing-lambda
Votre code ressemblerait alors à ceci (avertissement: brain compile):
la source
Ma solution, utilisez simplement un pointeur de fonction pour faire référence à un lambda statique.
la source
J'ai trouvé une réponse ici: http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
Il convertit
lambda pointer
àvoid*
et à l' arrière de conversion en cas de besoin.à
void*
:auto voidfunction = new decltype (to_function (lambda)) (to_function (lambda));
de
void*
:fonction automatique = static_cast <std :: function *> (voidfunction);
la source