Tout est dans le titre.
J'aimerais avoir vos avis.
merci
Tout est dans le titre.
J'aimerais avoir vos avis.
merci
Ben, en C++, tant qu'on aura pas un support bien officiel dans le langage des fonctions lambda et closures, ce sera toujours lourd à l'écriture.
Mais sinon, utiliser une fonction d'ordre supérieur, c'est toujours plus agréable que d'écrire la boucle à la main, et souvent plus élégant, tu évites les erreurs (même si dans le cas des boucles idiomatiques, c'est très rare), et on sait explicitement ce que tu fais, parce qu'une fonction d'ordre supérieur a un nom.
L'avantage est qu'un foncteur est réutilisable, et qu'il peut maintenir un état.
Puis, l'avantage par rapport à une fonction tout court, c'est que c'est plus facile d'inliner.
Pour autant, je n'écris presque jamais de foncteur directement, parce que je trouve que le gain par l'inlining se justifie très peu souvent (EDIT : et au prix d'une écriture lourde).
S'il faut maintenir un état pour la fonction, je préfère currifier mes fonctions (avec [std|boost]::bind).
-------
Dans un langage fonctionnel, il n'y aurait pas de question à se poser, on manipule toujours des fonctions d'ordre supérieur, le code est concis.
Le problème vient de C++, c'est tout.
Idem. Je dirais, en C++98/C++03 : Pas encore. En C++0x, très probablement.
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
Pour moi, la lourdeur de l'écriture des algo et functor rend le code peut lisible.
Cela peut devenir même illisible lorsqu'il s'agit de code écrit par quelqu'un d'autre !
Le problème de la maintenance de ce type de construction est le plus critique. Lorsque le code est 'simple' classique, les adaptation et modification sont facile a faire, par contre, lorsque l'on doit modifier le comportement d'un morceau de code contenant 3 ou 4 algo combinés (plus tous les functors adapteurs nécessaires), la modification est quasiment impossible.
Je ne sais pas trop, je pense que chacun à ses préférences, mais moi j'utilise des foncteurs de plus en plus. Et je crois que si les noms de ces foncteurs sont explicite, ça n'enlève rien à la compréhension du code, voire même ça peut l'améliorer.
Je que je fais, c'est que je met mes foncteurs dans l'en-tête de la classe à laquelle avec laquelle ils sont en relation. Ca reste ainsi une même entité.
Outre les avantages cités ci-dessus, je rejouterai que ça peut permettre de simplifier l'interface d'une classe (interface dans le sens: "ensemble des fonctions membres publiques"). En effet, l'utilisation de foncteurs permet d'écrire une fonctionalité complexe en une ligne (notemment pour l'utilisation des algorithmes de la STL). Sans foncteur, cette fonctionnalité va certainement nécessité une fonction membre supplémentaire.
Je ne sais pas si je m'explique bien, je suis mal réveillé![]()
Pareil qué miguel.
Tout pareil: en fait, cela permet aussi de déporter des traitements internes d'une classe dans une classe associée (le functor). Donc comme dit r0d, l'interface de la classe se réduit de plus en plus aux services proposées et est expurgées des méthodes internes de pur implémentation. Le graal étant d'avoir une classe avec que des méthodes publiques, les détails d'implémentation étant masqués.
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
Ça me fait penser à un travail de réecriture que j'ai réalisé récemment.
J'ai remplacé du code du style
par
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 marcel_bubble_t* bubble = 0; int max_load = -1; marcel_entity_t* e; for_each_entity_in_bubble_begin(entities, e) { if(e->type == MA_ENTITY_BUBBLE) { marcel_bubble_t* b = marcel_bubble_entity(e); if(is_interesting_bubble(b)) { int load = ma_entity_load(e); if(load > max_load) { max_load = load; bubble = b; } } } } for_each_entity_in_bubble_end;
Pour moi il est évident que la seconde forme est plus sûre, car idiomatique, et plus facile à maintenir, car à la fois concise et exprimant clairement ce qu'elle fait.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 bubble_ptr bubble = deref_def(max_element( entities | match<bubble_ptr>() | filtered(is_interesting_bubble), load(_1) < load(_2) ));
Mais les développeurs, réticent à apprendre de nouvelles manières de programmer, ont préféré la première parce qu'ils ne comprenaient pas la deuxième, et qu'ils connaissaient pas les bibliothèques qu'elle exploitait.
Aucune des deux ne me semblent idiomatique en C++. La première m'a l'air écrite en C, la deuxième... en Lisp (a part que fermer des parenthèses sur une ligne autrement vide ne se fait pas en Lisp). En C++, si elle a certainement dépassé le stade purement expérimental -- il y a une sous-communauté, apparemment grandissante et en tout cas influente pour laquelle ce genre d'écriture est la marque de fabrique --, elle n'est pas encore la manière coutumière d'écrire du code. Même si elle fini par s'imposer hors de sa province, ce qui n'est pas encore certain, je doute que ce soit avant que le C++ 0X soit bien répandu -- ce qui prendra encore quelques années.
Tu as l'air d'accord avec moi. Si c'est une nouvelle manière de programmer, ce n'est pas idiomatique (mais comme je l'ai déjà écrit, ça ressemble plus à du C qu'à du C++ quand même).Mais les développeurs, réticent à apprendre de nouvelles manières de programmer, ont préféré la première parce qu'ils ne comprenaient pas la deuxième, et qu'ils connaissaient pas les bibliothèques qu'elle exploitait.
Abuser? Jamais. Si tu considères que c'est abuser, tu donnes déjà la réponse.Doit on abuser des algo et des foncteurs?
Après, le degré d'utilisation qui fait dépasser le niveau de l'abus change suivant le contexte. Le C++ est trop utilisé pour qu'il n'y ait pas de variation à ce genre de choses suivant le contexte.
C'est idiomatique dans la mesure où on met en place des idiomes et on les utilise.
Écrire le code à la main, pour moi il n'y a pas d'idiome.
Sinon, c'est juste une utilisation de Boost.RangeEx (qui est dans la review queue), qui fournit des adaptateurs de ranges avec une syntaxe infixe à l'aide de l'opérateur "pipe".
La réponse est : cacahuète. Je veux dire, la réponse est dans la question; doit on en abuser ? la connotation négative de abuser dit tout
Quand on a le choix, c'est toujours une erreur de se brider en se forcant a utiliser toujours l'une. donc, pas tout foncteur, pas tout boucle for.
La limite dépend ensuite des personnes; certaines trouvent ca compliqué a lire, d'autres trouvent ca trop long a ecrire, une vieille boucle for faisant aussi le boulot.
On a envie de faire comme en python des fois :
les foncteurs sont loins de cette qualité d'ecriture, mais parfois plus pratique que
Code : Sélectionner tout - Visualiser dans une fenêtre à part list = [1/i for i in list if i != 0]
enfin, je ne sais pas, ca depend des gens.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 for(std::vector<int>::iterator it = list.begin(); it != list.end(); ++it) { if(*it != 0) *it = 1/*it; }
C'est aussi une question de gymnastique. Si tu n'en connais pas les principes, alors tu comprends beaucoup moins le code mis en œuvre. Mais une fois que tu es familier avec les principes, alors en général, paradoxalement, le code gagne en clarté et la conception est plus cohérente. Pour moi, le seul bémol, c'est que c'est parfois un peu délicat à debugger lorsqu'on veut entrer dans les algos plus en détail.
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
ça peut s'exprimer avec par exemple
Code : Sélectionner tout - Visualiser dans une fenêtre à part [1/i for i in list if i != 0]
Code : Sélectionner tout - Visualiser dans une fenêtre à part list | filtered(_1 != 0) | transformed(1/_1);
http://boost-sandbox.sourceforge.net...tml/index.html
Documentation pas à jour encore.
Il faut fournir des foncteurs. Après tu te débrouilles comme tu veux pour les générer.Par contre, comme d'habitude, si tu manipules des choses plus compliquées que des [int|float|double|char], comme des structures, on doit se taper des (&Type:: ) ?
L'idéal c'est quand même d'éviter les pointeurs vers les membres un maximum, c'est quand même super moche ces trucs-là (en plus d'être assez inefficace sur certains compilateurs et non polymorphe).
Partager