L'idée de la technique proposée ici n'est pas de moi mais bien de Bjarne Stroustrup. Je suis tombé dessus en lisant son sympathique livre Programming principles and practice using C++.
Dans ce qui suit, j'utilise à l'occasion std::numeric_limits, un trait défini pour tous les types primitifs numériques du langage C++ (et extensible à d'autres types, au besoin) que vous trouverez dans l'en-tête standard <limits>. J'omettrai le préfixe std:: pour alléger l'écriture.
Certaines opérations sont fondamentalement à risque de résulter en une perte de précision. Un exemple simple est proposé à droite, où l'affectation de s à i est sans risque mais l'affectation de i à s peut poser problème. De même, l'affectation de i à ui peut mener à une perte de précision, et il en va de même pour l'affectation de ui à i. La raison pour laquelle ces risques existent (ou non) a trait aux domaines de ces variables :
La norme du langage C++ ne fixe pas les tailles (ou les bornes) pour ces types, mais elle fixe toutefois certaines relations :
|
|
Valider une affectation d'une donnée d'un type à un autre n'est donc pas nécessairement une question de types. C'est d'abord une question de valeur. L'exemple proposé à droite met ceci en relief :
|
|
Un tel débordement est sournois, car il est le plus souvent silencieux. Il arrive même que des programmeurs profitent de cette propriété pour faire des optimisations (je suis coupable de certaines d'entre elles!) alors il n'est pas clair que nous souhaitions les pénaliser systématiquement. Cependant, dans le cas où un débordement poserait problème, il serait bien de pouvoir le détecter et, le cas échéant, lever une exception.
Dans son livre Programming principles and practice using C++, Bjarne Stroustrup propose une technique toute simple pour obtenir précisément ce comportement. Cette technique se décline sous la forme d'une opération de transtypage maison (un Cast) qu'il nomme le narrow_cast, du terme anglais narrowing. Le principe est simple :
|
|
Reprenons l'exemple plus haut :
Mission accomplie! |
|
Simple et, dans les circonstances, plutôt efficace.