Posté le 20/12/2015 à 17:32 Membre depuis le 18/06/2001, -26239 message
yop,

Je suis tombé sur cet article : http://fr.cppreference.com/w/cpp/language/lambda
Est-ce que c'est une killer feature qu'il faut absolument connaitre et comprendre, ou est-ce qu'à mon petit niveau on s'en passe allègrement ?
Ca parait bête de demander ça, mais j'ai du mal à trouver des exemples intéressants qui me concernent, et qui pourraient me simplifier les choses au niveau du design.

Alors qu'en pensez-vous de cette "nouveauté", et si possible, pourriez-vous me donner un cas un peu plus intéressant qu'une fonction qui ajoute 10 pour illustrer vos propos ? Merci bien. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/12/2015 à 18:13 Membre depuis le 13/06/2002, 42484 messages
Oui c'est très pratique pour injecter des petits bouts de code dans une fonction. De cette façon tu peux combiner des comportements et réutiliser ton code plus efficacement qu'avec par exemple de l'héritage. Un petit exemple cas d'école : mettons que tu codes la fonction de tri la plus rapide de l'univers. Tu aimerais bien qu'elle soit capable de trier une liste de n'importe quel type, encore faut-il définir comment on compare deux objets de ce type entre eux pour savoir lequel est le plus grand. Ça ne fait pas tellement partie de l'algorithme de tri, et de toutes façons tu ne peux pas connaître à l'avance tous les objets qu'on aura envie de trier avec ta fonction.

Une solution consiste à laisser l'utilisateur de ta fonction passer en paramètre, en plus de la liste à trier, une fonction de comparaison qui permet de déterminer entre deux objets lequel est le plus grand. Lors de l'utilisation de ta fonction de tri, passer cette fonction de comparaison via une lambda sera facile et lisible.

Voilà la signature de ta fonction de tri qui trie des objets de type "T". Elle prend un vecteur d'instances de "T" (items) et une fonction qui prend deux objets "T" et me retourne -1 si le premier est plus petit, 0 s'ils sont égaux ou 1 si le deuxième est plus petit :
template<typename T>
maSuperFunctionDeTri(vector<T>* items, function<int (const T&, const T&)> compare);

Ensuite je veux trier un vecteur de comptes utilisateur de yAronet en fonction de leur login. Rien de plus simple, je passe une fonction "compare" qui se base sur le login pour déterminer l'ordre entre deux utilisateurs (en délégant la comparaison à la fonction "compare" du type std::string qui fait exactement ce que je veux) :
maSuperFunctionDeTri(&accounts, [] (const Account& yaronaute1, const Account& yaronaute2)
{
    return yaronaute1.login.compare(yaronaute2.login);
});

Maintenant si je veux comparer en fonction de leur nombre de posts plutôt que le login, je n'ai qu'à changer la lambda :
maSuperFunctionDeTri(&accounts, [] (const Account& yaronaute1, const Account& yaronaute2)
{
    if (yaronaute1.posts < yaronaute2.posts)
        return -1;
    else if (yaronaute1.posts > yaronaute2.posts)
        return 1;
    else
        return 0;
});
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Posté le 20/12/2015 à 18:27 Membre depuis le 18/06/2001, -26239 message
Merci beaucoup ! Ah c'est pas mal en effet. J'ai l'impression que ça peut avantageusement remplacer les templates par endroits, perso ça me va très bien.
J'ai lu ça aussi : http://www.cprogramming.com/c++11/c++11-lambda-closures.html
L'explication est très "progressive", en fait même pour des cas très simples, ça peut être bien... (mais j'imagine vite crade si on déclare des lambdas à tout va parce qu'on a la flemme d'aller dans le header déclarer proprement une méthode privée ^^)

Bon ben impeccable, je vais essayer de m'entrainer à rajouter cette corde à mon arc, merci bien. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/12/2015 à 18:36 Membre depuis le 03/11/2002, 14435 messages
Ce n'est pas indispensable mais ça simplifie le développement de callbacks (il suffit de passer une fonction, qui a accès aux variables locales englobantes) et pour le reste ça sert pour ceux qui viennent de la programmation fonctionnelle.
Folco (./3) :
(mais j'imagine vite crade si on déclare des lambdas à tout va parce qu'on a la flemme d'aller dans le header déclarer proprement une méthode privée ^^)
Ce n'est pas du tout fait pour ça. Tu t'en rendras compte en pratiquant.
avatarHighway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741
Posté le 20/12/2015 à 18:42 Membre depuis le 13/06/2002, 42484 messages
Heu oui en effet j'ai complètement passé sous silence la partie closure qui était aussi dans ton titre, my bad ^^
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Posté le 20/12/2015 à 18:50 Membre depuis le 18/06/2001, -26239 message
C'est pas grave, j'en suis encore à la découverte, merci à vous grin

Au fait, pourquoi cette question ? Parce que j'ai créé un nouveau porojet sous Codelite, et qu'il propose quelques wizards, notamment pour les projets "Cobra". J'ai googlé "Cobra Compiler", puis j'ai trouvé les listes en compréhension, les générateurs, et enfin ces fameuses closures. C'est en voyant qu'il y avait un exemple en C++ que j'ai décidé de creuser la question. Vive internet ! trioui
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/12/2015 à 19:58Edité par PpHd le 20/12/2015 à 20:15 Membre depuis le 11/06/2001, 19563 messages
Folco (./1) :
qui pourraient me simplifier les choses au niveau du design.
Arg!!! On ne parle pas de design lorsqu'on fait du code !
Posté le 20/12/2015 à 20:09 Membre depuis le 10/06/2001, 40014 messages
Comme on peut affecter un lambda à une variable locale ou une variable membre d'instance, ils peuvent aussi servir de closures. Notamment, si tu travailles avec une interface faite pour le C++11, qui accepte donc une std::function et n'a pas forcément besoin d'un vrai pointeur de fonction (style C, ce que les lambdas C++11 ne sont pas!), un tel lambda peut remplacer une fonction imbriquée (nested function), ce dernier concept n'étant pas géré par les compilateurs C++ courants (et en C, en gros seulement par GCC, g++ ne le gérant pas).
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 20/12/2015 à 20:13 Membre depuis le 18/06/2001, -26239 message
PpHd (./7) :
Arg!!! On ne parle pas de design lorsqu'on fait du code !
Désolé, je suis pas pro, j'ai des lacunes évidentes en analyse. Ceci dit, je veux bien le titre d'un bouquin en français qui apprend à faire correctement de l'analyse. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/12/2015 à 20:30 Membre depuis le 03/11/2002, 14435 messages
(Brrr ce genre de réaction est trop calculé Folco, c'est pas la première fois que je vois, lâche toi un peu !)

Sinon on peut parler d'API design et les lambdas peuvent les simplifier.
avatarHighway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741
Posté le 20/12/2015 à 20:30 Membre depuis le 18/06/2001, -26239 message
(hé ho grin)
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/12/2015 à 23:08 Membre depuis le 10/06/2001, 40014 messages
D'ailleurs, le fait que les lambdas C++11 ne sont pas des pointeurs (de fonction) (mais des objets, de la classe template std::function) a l'avantage qu'on n'a pas besoin de construire dynamiquement une fonction tremplin (trampoline) sur la pile (stack), et donc de rendre la pile exécutable. À la place, on passe de vrais objets qui peuvent contenir plus d'informations qu'un simple pointeur à appeler directement.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 21/12/2015 à 00:52 Membre depuis le 27/04/2006, 59488 messages
./2 : c'est marrant, parce que ton exemple est en fait déjà prévu par le C89 hehe :
http://www.bien-programmer.fr/qsort.htm
(bon c'est une callback avec des void *, donc c'est moins propre et pas hype, mais le principe est le même)

Par contre, avoir accès aux variables locales de l'appelant, ça poutre (c'est un vrai manque en C, je trouve).
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo
Posté le 21/12/2015 à 09:33 Membre depuis le 13/06/2002, 42484 messages
Oui rien de nouveau si ce n'est la syntaxe, tant que Folco n'utilise pas de closures les lambdas ne permettent rien que de simples pointeurs sur fonction n'offraient pas déjà smile
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Posté le 21/12/2015 à 11:20 Membre depuis le 30/06/2001, 70810 messages
Zerosquare (./13) :
./2 : c'est marrant, parce que ton exemple est en fait déjà prévu par le C89 hehe :
http://www.bien-programmer.fr/qsort.htm
(bon c'est une callback avec des void *, donc c'est moins propre et pas hype, mais le principe est le même)
Par contre, avoir accès aux variables locales de l'appelant, ça poutre (c'est un vrai manque en C, je trouve).

Le probleme c'est que en C ca marche a merveille, en C++ "normal" les callbacks sont une misere a utiliser/faire
avatarProud to be CAKE©®™
The cake is a lie! - Love your weighted companion cube

->986-Studio's Wonder Project!<-
yN a cassé ma signature :o
Posté le 21/12/2015 à 11:26 Membre depuis le 13/06/2002, 42484 messages
Par exemple ?
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Posté le 21/12/2015 à 11:31 Membre depuis le 30/06/2001, 70810 messages
En C++ host C++11 et joyeuseté recente, comment tu fais dans une GUI pour proposer un callback?

Sachant que le callback doit, bien sur, appeler une méthode d'un objet?
avatarProud to be CAKE©®™
The cake is a lie! - Love your weighted companion cube

->986-Studio's Wonder Project!<-
yN a cassé ma signature :o
Posté le 21/12/2015 à 12:55 Membre depuis le 13/06/2002, 42484 messages
Soit je comprends pas le problème, soit https://en.wikipedia.org/wiki/Function_pointer#Method_pointers ?
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Posté le 21/12/2015 à 14:02 Membre depuis le 03/11/2002, 14435 messages
C'est effectivement ça, mais c'est pas beau (et là tu dois en plus spécifier le type de classe qui sera passé, sinon il te faut utiliser la généricité mais ça veut dire tout implémenter dans le .hpp donc des perfs de compilation à chier, des PCH de merde énormes et pas combinables). Pour un toolkit GUI ça devient une misère, impossible de designer proprement.
int bar1(int i, int j, Foo* pFoo, int(Foo::*pfn)(int,int))
{
    return (pFoo->*pfn)(i,j);
}
avatarHighway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741
Posté le 21/12/2015 à 19:53 Membre depuis le 10/06/2001, 40014 messages
La solution classique, ce sont les callbacks avec un argument supplémentaire void *userdata qui est repassé par le code qui appelle le callback tel qu'il l'a reçu. En C++, on a ensuite un wrapper de type:
void cb_foo(int i, void *userdata) {
  static_cast<MyClass *>(userdata)->foo(i);
}

En C, userdata est généralement une structure construite spécialement pour ce callback, c'est encore plus crade, mais c'est pour ça que ça a été conçu à la base.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 21/12/2015 à 20:49 Membre depuis le 30/06/2001, 70810 messages
C'est... immonde tout simplement et completement a l'encontre du principe objet
avatarProud to be CAKE©®™
The cake is a lie! - Love your weighted companion cube

->986-Studio's Wonder Project!<-
yN a cassé ma signature :o
Posté le 21/12/2015 à 20:57 Membre depuis le 18/06/2001, -26239 message
Il dit que c'est crade, oui ^^
A l'encontre du "principe objet", je vois pas trop, mais si tu le dis. Par contre, ça doit être de loin ce qu'il y a de plus efficace une fois assemblé tongue
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 21/12/2015 à 21:03 Membre depuis le 30/06/2001, 70810 messages
Pas sur j'ai l'impression qu'il dit que le cote crade est en C
avatarProud to be CAKE©®™
The cake is a lie! - Love your weighted companion cube

->986-Studio's Wonder Project!<-
yN a cassé ma signature :o
Posté le 21/12/2015 à 21:16 Membre depuis le 10/06/2001, 40014 messages
"encore plus crade" implique que la solution C++ est crade aussi. C'est une bidouille pour utiliser les APIs style C en C++.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité