Nous avons examiné en classe un exemple de fonction générique moyenne(), opérant à partir d'itérateurs et de traits. L'exemple à droite est fonctionnel, à ceci près que je n'ai implémenté les traits reel_type et cumul_type que pour un seul type (vous pourrez l'enrichir à votre convenance, évidemment). Notez que l'implémentation à droite utilise auto pour déduire le type de n à partir du type de std::distance(debut,fin), ce qui est bien plus léger que ne le serait le recours aux traits du type d'itérateur It. Sur un compilateur pré-C++ 11, toutefois, les traits auraient été l'option à privilégier. Notez aussi qu'avant C++ 11, les fonctions std::begin() et std::end() n'étaient pas offertes de manière standard. On aurait toutefois pu exprimer quelque chose de semblable en déduisant la taille du tableau tab dès la compilation :
Remarquez au passage le recours à des alias de types avec using. Cette pratique, possible depuis C++ 11, permet d'alléger significativement l'écriture des types génériques complexes. Ainsi, plutôt que d'écrire ceci :
... on peut maintenant écrire cela :
... du fait que reel_type_t<T> est défini comme équivalent à typename reel_traits<T>::type. Le gain de simplicité est appréciable. |
|
Vous avez peut-être remarqué que cumul_traits est quelque peu risqué, parce qu'il est ardu de savoir à la compilation du code serveur quels seront les besoins effectifs de cumul du code client. Le raffinement à droite couvre (avantageusement) cette particularité. Pour cumuler sur un autre type que le cumul_type planifié, il suffit d'offrir une surcharge de la fonction moyenne(), celle-ci prenant un troisième paramètre dont le type sera celui désiré et dont la valeur initiale sera appropriée. Évidemment, il est alors plus simple (et sans risque de perte de performance ou de généralité) d'implémenter la version à deux paramètres comme un cas particulier du cas à trois paramètres... Notez que, dans un cas comme dans l'autre, cet exemple peut être amélioré d'au moins deux importantes manières :
|
|
L'amélioration la plus immédiate ici consiste sans doute à passer par std::accumulate() pour réaliser le cumul des valeurs. Ce faisant, le code tout entier de la fonction moyenne() devient une seule expression combinant le cumul des valeurs et le nombre d'éléments dans la séquence sur laquelle la fonction opère. Il ne reste même plus de variable locale à cette fonction! |
|