En passant de la capture lambda comme pointeur de fonction
Est-il possible de passer d'une fonction lambda comme un pointeur de fonction? Si oui, je dois être en train de faire quelque chose incorrecte parce que je suis une erreur de compilation.
Considérons l'exemple suivant
using DecisionFn = bool(*)();
class Decide
{
public:
Decide(DecisionFn dec) : _dec{dec} {}
private:
DecisionFn _dec;
};
int main()
{
int x = 5;
Decide greaterThanThree{ [x](){ return x > 3; } };
return 0;
}
Quand je essayez de compiler ce, j'obtiens l'erreur de compilation suivante:
In function 'int main()':
17:31: error: the value of 'x' is not usable in a constant expression
16:9: note: 'int x' is not const
17:53: error: no matching function for call to 'Decide::Decide(<brace-enclosed initializer list>)'
17:53: note: candidates are:
9:5: note: Decide::Decide(DecisionFn)
9:5: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'DecisionFn {aka bool (*)()}'
6:7: note: constexpr Decide::Decide(const Decide&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const Decide&'
6:7: note: constexpr Decide::Decide(Decide&&)
6:7: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'Decide&&'
C'est un diable d'un message d'erreur à digérer, mais je pense que ce que je suis en sortir, c'est que le lambda ne peut pas être traité comme un constexpr
donc je ne peut pas passer comme un pointeur de fonction? J'ai essayé de faire x
const ainsi, mais cela ne semble pas aider.
lambda peut se désintègrent en pointeur de fonction que s'ils ne captent rien.
blogs.msdn.com/b/oldnewthing/archive/2015/02/20/10594680.aspx
blogs.msdn.com/b/oldnewthing/archive/2015/02/20/10594680.aspx
OriginalL'auteur CoryKramer | 2015-02-26
Vous devez vous connecter pour publier un commentaire.
Un lambda ne peut être converti en un pointeur de fonction si elle ne rend pas compte de la projet de C++11 section
5.1.2
[expr.prim.lambda] dit (accent mine):Note, cppreference couvre également, dans leur article sur Lambda fonctions.
Donc l'alternative suivante devrait fonctionner:
et alors serait-ce:
et comme 5gon12eder points, vous pouvez également utiliser
std::function
, mais note questd::function
est poids lourd, de sorte qu'il n'est pas un coût moins compromis.void*
comme seul paramètre. Il est normalement appelé par l'utilisateur "pointeur". Il est relativement léger, trop, mais ça a tendance à exiger que vousmalloc
hors de l'espace.OriginalL'auteur Shafik Yaghmour
Shafik Yaghmour réponse correctement explique pourquoi le lambda ne peut pas être passé comme un pointeur de fonction si elle a une capture. J'aimerais vous montrer deux simples correctifs pour le problème.
Utilisation
std::function
au lieu de raw pointeurs de fonction.C'est très propre solution. Notez cependant qu'il comprend des surcharges supplémentaires pour le type d'effacement (probablement un appel de fonction virtuelle).
Utiliser une expression lambda qui ne capture rien.
Depuis votre prédicat est vraiment juste un booléen constante, ce qui suit rapidement un travail autour de la question actuelle. Voir cette réponse pour une bonne explication pourquoi et comment cela fonctionne.
Voir ce question pour plus de détails pourquoi il fonctionne
Oui, je sais. J'ai eu à vérifier [plus.construit]/p25 pour vérifier qu'il y a un haut-candidat pour les pointeurs de fonction.
J'ai été fasciné la première fois que j'ai vu que le travail moi-même et j'ai donc ajouté le commentaire pour ceux qui ne veulent pas passer par la peine de comprendre pourquoi ça fonctionne, mais sont curieux et il est bon de savoir au moins jusqu'à Visual Studio 2013, cela ne fonctionne pas à cause d'un bug. Je n'avais pas de doutes que vous pourriez le comprendre vous-même 😉
Belle réponse que vous avez lié à, +1. Je vais ajouter un lien vers ma réponse.
OriginalL'auteur 5gon12eder
Je connais un peu cette vieille..
Mais je voulais ajouter:
Expression Lambda (même capturé) peut être traitée comme un pointeur de fonction!
Il est délicat, car une expression Lambda n'est pas une fonction simple. Il est en fait un objet avec un opérateur().
Lorsque vous êtes créatif, vous pouvez utiliser cette!
Penser à une "fonction" de la classe dans le style de std::function.
Si vous enregistrez l'objet!
Vous pouvez également utiliser le pointeur de fonction.
D'utiliser le pointeur de fonction, vous pouvez utiliser les éléments suivants:
De construire une classe qui peut commencer à travailler comme un "std::function" je vais faire court exemple. D'abord vous avez besoin d'un class/struct que peut stocker de l'objet et de la fonction pointeur également vous besoin d'un opérateur() pour l'exécuter:
Avec cela, vous pouvez maintenant exécuter capturé, noncaptured lambdas, tout comme vous utilisez la version originale:
Ce code fonctionne avec VS2015
Espérons que cela aide : )
Accueille!
Edit: retiré les aiguilles modèle FP, a supprimé la fonction de pointeur de paramètre, renommé pour lambda_expression
Mise à jour 04.07.17:
J'ai ajouté une version courte de mon propre code. ce devrait être le travail avec un simple auto f = faire::function(lambda); Mais je suis tout à fait shure, vous trouverez beaucoup de situation mon code ne fonctionne pas. std::function, c'est bien plus bien construit que cela, et devrait être l'aller pour quand vous êtes au travail. C'est ici pour l'éducation et pour une utilisation personnelle.
Cette solution implique l'appel de la lambda via un
operator()
mise en œuvre, donc, si je suis en train de lire ce droit, je ne pense pas que cela fonctionnerait pour appeler le lambda à l'aide d'un C-style pointeur de fonction, le serait-il? Qu'est ce que le l'original de la question posée.Vous l'avez réclamé que les lambdas peuvent être traités comme des pointeurs de fonction, que vous n'avez pas le faire. Vous avez créé un autre objet de tenir un lambda, qui ne fait rien, vous pourriez ai simplement utilisé l'original lambda.
Ce n'est pas "en passant de la capture lambda comme pointeur de fonction". C'est le "passage de la capture lambda comme un objet qui contient un pointeur de fonction entre autres choses". Il y a un monde de différence.
OriginalL'auteur Noxxer
Capture lambdas ne peuvent pas être convertis à des pointeurs de fonction, comme cette réponse souligné.
Cependant, il est souvent assez difficile à fournir un pointeur de fonction à une API qui n'accepte qu'un seul. Le plus souvent cité méthode pour le faire est de fournir une fonction et d'appeler un objet statique avec elle.
C'est fastidieux. Nous profitons de cette idée plus loin et d'automatiser le processus de création de
wrapper
et de rendre la vie beaucoup plus facile.Et l'utiliser comme
Live
C'est essentiellement à la déclaration d'une fonction anonyme à chaque occurrence, de
fnptr
.Noter que les invocations de
fnptr
remplacer le déjà écritcallable
donné callables du même type. Nous y remédier, dans une certaine mesure, avec laint
paramètreN
.OriginalL'auteur Passer By
Bien que le modèle de l'approche est intelligente, pour diverses raisons, il est important de rappeler le cycle de vie de la lambda et la capture de variables. Si toute forme de lambda pointeur est va être utilisé et le lambda n'est pas une baisse de la poursuite, alors qu'une copie de [=] lambda doit être utilisé. I. e., même alors, la capture d'un pointeur vers une variable sur la pile est DANGEREUX si la durée de vie de ceux capturés pointeurs de pile (déroulement) est plus courte que la durée de vie de la lambda.
Une solution plus simple pour la capture d'un lambda comme un pointeur est:
auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
par exemple,
new std::function<void()>([=]() -> void {...}
Rappelez-vous juste pour plus tard
delete pLamdba
afin de s'assurer que vous n'avez pas de fuite le lambda de la mémoire.Secret de réaliser ici, c'est que les lambdas peuvent capturer des lambdas (demandez-vous comment cela fonctionne) et aussi que, pour
std::function
de travailler de façon générique le lambda de la mise en œuvre doit contenir suffisamment d'information interne pour fournir l'accès à la taille de la lambda (et enregistrées) de données (c'est pourquoi l'delete
devrait fonctionner [en cours d'exécution des destructeurs de la capture de types]).OriginalL'auteur smallscript
Comme il a été mentionné par les autres, vous pouvez remplacer la fonction Lambda au lieu de pointeur de fonction. Je suis à l'aide de cette méthode dans mon interface C++ pour F77 solveur ODE RKSUITE.
OriginalL'auteur beniekg
Un raccourci pour l'utilisation d'un lambda comme C le pointeur de fonction est ceci:
À l'aide de Curl comme exmample (curl les informations de débogage)
+
astuce vous permet de vous).OriginalL'auteur janCoffee