En effet, en C++ tous les types numériques sont implicitement castables en un autre type numérique, et comme les enums et les bools sont des types numériques, cela devient vite comique. Tu peux cependant activer des warnings quand ces conversions font de la perte d'information, mais c'est simplement un warning et surtout il dépend du compilateur :
λ skyskolem ~ → clang++ test_conv.cpp -Wall -Wextra -Wall -Wconversion
test_conv.cpp:5:5: warning: implicit conversion from 'double' to 'bool' changes value from 3.5 to true
[-Wliteral-conversion]
if(3.5)
~~ ^~~
test_conv.cpp:7:17: warning: implicit conversion from 'double' to 'int' changes value from 3.5 to 3
[-Wliteral-conversion]
add(2, false, 3.5);
~~~ ^~~
2 warnings generated.
(note: j'avoue que je n'ai pas cherché si il existe un ensemble de flags pour en trouver plus).
À cela j'ajoute un piège dans lequel beaucoup de développeurs C++ tombent facilement c'est que par définition en C++ un constructeur à un argument est un opérateur de cast implicite :
Ce problème se règle en préfixant les constructeur du mot clé explicit, mais l'oubli est facile.
Pour finir ce message, je voudrais expliquer comment cela fonctionne dans Haskell. C'est la même situation qu'en OCaml au sens que les conversions implicites n'existent pas. Cependant en ce qui concerne les literaux numériques c'est un peu particulier, ceux-ci sont polymorphiques, ce qui veut dire que 2 est potentiellement un Float/Double/Int/Integer/Int32/Word16 et cela ne sera décidé que par le biais de l’inférence de type, en gros c'est la fonction qui prendra notre literal en paramètre qui décidera de son sort.
Notons cependant que ce choix est fait en fonction du literal. En gros, 3 peut être un Double, mais 3.2 ne peut pas être un Int, exemples, avec deux fonctions:
C'est un beau compromis dans le sens où il n'est pas nécessaire de typer explicitement ses literaux, mais aucun cast implicite n'est effectué. En contrepartie il faut de temps à autre être explicite sur le type car l'inférence de type s'y perd.
C'est aussi pratique quand on commence à implémenter ses propres types numériques pour différents cas de figure (calcul vectoriel, auto differentiation, ...) et où il est agréable de profiter de l'écriture de litéreaux. Exemple non complet, soit une fonction f :
fv=2*(v*v)
Le type inferé par Haskell est f :: Num a => a -> a. En gros, une fonction qui prend un Num et retourne un Num.
Cela fonctionne pour les littéraux "classiques" :
Prelude>f28Prelude>f2.310.579999999999998
Mais j'ai aussi définis mon type numérique maison Expr Float qui représente un arbre d'expression et je peux utiliser f dessus :
[^] # Re: Jai: Language for game programmming
Posté par Guillaum (site web personnel) . En réponse à la dépêche C++17, Genèse d’une version mineure. Évalué à 8.
Yahoo, je suis enfin reconnu par mes pairs ;)
En effet, en C++ tous les types numériques sont implicitement castables en un autre type numérique, et comme les enums et les bools sont des types numériques, cela devient vite comique. Tu peux cependant activer des warnings quand ces conversions font de la perte d'information, mais c'est simplement un warning et surtout il dépend du compilateur :
La compilation avec
clangnous donne :(note: j'avoue que je n'ai pas cherché si il existe un ensemble de flags pour en trouver plus).
À cela j'ajoute un piège dans lequel beaucoup de développeurs C++ tombent facilement c'est que par définition en C++ un constructeur à un argument est un opérateur de cast implicite :
Ce problème se règle en préfixant les constructeur du mot clé
explicit, mais l'oubli est facile.Pour finir ce message, je voudrais expliquer comment cela fonctionne dans Haskell. C'est la même situation qu'en OCaml au sens que les conversions implicites n'existent pas. Cependant en ce qui concerne les literaux numériques c'est un peu particulier, ceux-ci sont polymorphiques, ce qui veut dire que
2est potentiellement unFloat/Double/Int/Integer/Int32/Word16et cela ne sera décidé que par le biais de l’inférence de type, en gros c'est la fonction qui prendra notre literal en paramètre qui décidera de son sort.Notons cependant que ce choix est fait en fonction du literal. En gros,
3peut être unDouble, mais3.2ne peut pas être unInt, exemples, avec deux fonctions:C'est un beau compromis dans le sens où il n'est pas nécessaire de typer explicitement ses literaux, mais aucun cast implicite n'est effectué. En contrepartie il faut de temps à autre être explicite sur le type car l'inférence de type s'y perd.
C'est aussi pratique quand on commence à implémenter ses propres types numériques pour différents cas de figure (calcul vectoriel, auto differentiation, ...) et où il est agréable de profiter de l'écriture de litéreaux. Exemple non complet, soit une fonction
f:Le type inferé par Haskell est
f :: Num a => a -> a. En gros, une fonction qui prend unNumet retourne unNum.Cela fonctionne pour les littéraux "classiques" :
Mais j'ai aussi définis mon type numérique maison
Expr Floatqui représente un arbre d'expression et je peux utiliserfdessus :Bon, je me suis encore lâché et j'ai expliqué pleins de trucs au lieu de regarder le meilleur pâtissier ;) Bonne soirée.