IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Conversion cast implicite et mot clef "explicit"


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 35
    Points
    35
    Par défaut Conversion cast implicite et mot clef "explicit"
    Salut !

    Tout le monde connaît les «*warning*» du type

    'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data

    ou leurs équivalents selon le compilateur.

    Je travaille en ce moment sur des types de nombres flottants en grande précision (double double et octuple précision). Bien sur, de la même façon qu'il est possible de «*caster*» un double en float, j'aimerais que ces types soit convertibles en double.

    Le problème c'est que j'aimerais interdire la conversion implicite. Autrement dit qu'il soit impossible d'écrire, par exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dd_real x = math::numerical_constants<dd_real>::pi();
    double y = x;
    mais seulement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dd_real x = math::numerical_constants<dd_real>::pi();
    double y = static_cast<double>(x);
    ou a la limite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dd_real x = math::numerical_constants<dd_real>::pi();
    double y = (double)x;
    Évidemment, mon opérateur de cast est codé dans la classe dd_real :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class dd_real
    {
      // ...
      operator double ()
      {
      // implementation
      }
      // ...
    };
    Un tel opérateur autorise le cast implicite.

    Dans le cas ou le cast est implémenté dans la classe vers laquelle on convertit, le mot clef peut être utilisé.
    Comment empêcher la conversion implicite vers double ?

    Je me doute qu'une façon de faire serait de définir une méthode "to_double" par exemple. Le problème c'est qu'on utilise ce type comme paramètre template de pas mal de code :

    -des templates à nous
    -des templates de la stl ou de boost

    Ces classes templates , par exemple la classe "floating_point_classification" de boost fait des conversions vers double par static_cast (et évidemment pas une méthode "to_double") avant d'appeler la méthode qui va bien sur double (typiquement pour le isnan). C'est ausi le cas dans l'implémentation de std::complex de visual c++ .

    Pour le moment, je résouds le problème salement en spécialisant des templates de boost ou de la stl pour le type qui m'intéresse !

    Je veux un mot clef explicit pour les opérateurs de cast !

    Quelqu'un a-t-il une méthode pour contourner la difficulté ?

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Avec l'opérateur de conversion tel que tu le décris, je ne vois pas vraiment de solution...

    Par contre, il y en a peut être une si tu envisage la création d'un foncteur (un objet fonction) qui effectue cette conversion.

    Associé, justement, au template et à la spécialisation partielle, il serait même possible de faire en sorte que la vérification soit faite au moment de la compilation

    Ainsi, tu pourrait envisager quelque chose proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /* nous déclarons la structure Converter pour tous les types */
    template <typename T>
    struct Converter;
    /* mais nous ne la définissons que pour les type "qui vont bien" 
     * (ici, un double)
     */
    template<>
    struct Converter<double>
    {
        double operator()(dd_real const & value)
        {
            /*...*/
        }
    };
    En ayant supprimé l'opérateur de conversion de ta classe dd_real, tu en arrivera à la situation suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main()
    {
        dd_real x = math::numerical_constants<dd_real>::pi();
        double y = x; // erreur, de compilation aucune conversion 
                      // implicite n'est possible
        int i = Converter<int>(x); // erreur de compilation: Converter<int> non défini
        double z= Converter<double>(x); //OK correctement défini et fait ce
                                        // ce que l'on attend de lui
    }
    [EDIT] au final, avec cette possibilité, tu devra "simplement" fournir une spécialisation pour les types dans lesquels dd_real est convertible.

    Mais tu ne devra le faire qu'une fois, car il "suffira" de passer un Converter<type> à une fonction ou à une classe template pour qu'elle le prenne en compte

    Et rien ne t'empeche de rajouter, pour les types provoquant une perte potentielle de données, un avertissement sous la forme d'une directive préprocesseur
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par nikopol82 Voir le message
    Je veux un mot clef explicit pour les opérateurs de cast !

    Quelqu'un a-t-il une méthode pour contourner la difficulté ?
    Attendre, en remontant vers ton fournisseur de compilateur que ça t'intéresserait de l'avoir assez vite ?

    C'est prévu dans le C++0x.

    Peut-être un bidouille est-elle possible en faisant un opérateur de cast vers un type intermédiaire et non directement vers double, puisqu'il ne peut-y avoir qu'un seul user-defined cast appliqué implicitement, pas deux, mais de toute façon, tous les compilateurs ne respectent pas cette règle.
    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.

  4. #4
    Nouveau membre du Club
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 35
    Points
    35
    Par défaut
    Ouah, je ne m'attendais pas à avoir une réponse si rapide !

    Merci pour vos réponse. Déjà ça m'apprend qu'il n'y a pas de solution complète dans la norme actuelle du langage.

    Pour l'instant, j'utilise une solution proche de celle proposée par koala01 dans les classes templates pour lesquelles j'ai la main (j'ai le droit de les changer), mais ça ne résoud pas le problème des classes templates comme celle de la stl, qui m'imposent d'implémenter cet opérateur de cast.

    Je vais jeter un oeil du coté de la norme C++0x. Ce code est compilé sur pas mal de compilateurs différents : Visual 2003; 2005 et 2008 coté windows et une version récente de gcc coté linux. (Sur certains projets, on reste sur des versions anciennes de visual à causes de bibliothèques tièrce partie)

    Apparemment du coté windows, il y a une extension C++0x à visual 2008, et coté gcc c'est déjà géré.
    Une petite macro MYEXPLICIT qui ne définit rien dans le cas des vieux compilos et qui définit explicit pour les compilos récents devrait résoudre le problème.

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Par contre, il y en a peut être une si tu envisage la création d'un foncteur (un objet fonction) qui effectue cette conversion.
    Si on veut respecter les noms classiquement utilisés pour ce genre de chose, comme lexical_cast, dynamic_pointer_cast... On pourrait l'appeler numeric_cast, ou un nom de ce genre. Mais ça ne résout pas le cas des fonctions existantes écrites avec un static_cast.
    Citation Envoyé par nikopol82 Voir le message
    Je vais jeter un oeil du coté de la norme C++0x. Ce code est compilé sur pas mal de compilateurs différents : Visual 2003; 2005 et 2008 coté windows et une version récente de gcc coté linux. (Sur certains projets, on reste sur des versions anciennes de visual à causes de bibliothèques tièrce partie)

    Apparemment du coté windows, il y a une extension C++0x à visual 2008, et coté gcc c'est déjà géré.
    Sauf que ces deux compilateurs ne gèrent que très partiellement C++0x (après tout, cette norme n'est pas encore sortie...) et je sais que VC++2010 ne gère pas encore cet aspect. Pour gcc, c'est normalement dans la version 4.5.

    En outre mon idée d'utiliser la double conversion ne marche pas. Tout ce qu'on peut faire, c'est que :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class IntermediateConverter;
     
     
    class SpecialDouble
    {
    public:
    	SpecialDouble(double val) : myVal(val) {}
    	double toDouble(){return myVal;}
    	operator IntermediateConverter();
    private:
    	double myVal;
    };
     
     
    class IntermediateConverter
    {
    public:
    	IntermediateConverter(SpecialDouble* specDouble) : mySpecDouble(specDouble) {}
    	operator double() {return mySpecDouble->toDouble();}
    private:
    	SpecialDouble *mySpecDouble;
    };
     
    SpecialDouble::operator IntermediateConverter()
    {
    	return IntermediateConverter(this);
    }
     
     
    int main()
    {
    	SpecialDouble sd(42);
    	//double d = sd; // Ne compile pas
    	double d = static_cast<IntermediateConverter>(sd); // Compile
    }
    Mais ce n'est pas ça que tu veux, puisque le code client cast en double, pas en IntermediateConverter.
    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.

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par nikopol82 Voir le message
    Pour l'instant, j'utilise une solution proche de celle proposée par koala01 dans les classes templates pour lesquelles j'ai la main (j'ai le droit de les changer), mais ça ne résoud pas le problème des classes templates comme celle de la stl, qui m'imposent d'implémenter cet opérateur de cast.
    Sauf erreur, si opérateur de transtypage il faut, il fait partie des paramètres templates potentiels de la fonction ou de la classe...

    Maintenant, je n'ai pas la prétention d'avoir la science infuse, donc, peut être pourrais tu me dire quelle partie de la stl a besoin de cet opérateur, histoire de pouvoir t'orienter correctement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Nouveau membre du Club
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 35
    Points
    35
    Par défaut
    Bonsoir,

    Voici un endroit dans dans la stl de MS ou on a besoin d'un cast vers double:
    Les traits pour instancier des complex<T>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
            // TEMPLATE CLASS _Ctraits
    template<class _Ty>
        class _Ctraits
        {    // complex traits for _Ty
    public:
             //...
        static bool __CLRCALL_OR_CDECL _Isnan(_Ty _Left)
            {    // test for NaN
            double _Tmp = (double)_Left;
            return (::_Dtest(&_Tmp) == _NANCODE);
            } 
             //...
        };
    Du coup, je surcharge _Ctraits pour dd_real ! Surtout que je ne pense pas que _CTraits soit une classe standard, mais qui n'existe que pour l'implémentation de visual, donc ce n'est pas du tout viable.

    On trouve pas mal d'autres exemples chez boost aussi (autour de la classe fonction fpclassify notemment. )

    S.

  8. #8
    Nouveau membre du Club
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 35
    Points
    35
    Par défaut
    En fait, je vais probablement faire cet opérateur de cast, au risque que les utilisateurs fassent des cast implicites.

    S.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. mot-clef static
    Par keil dans le forum C++
    Réponses: 8
    Dernier message: 25/01/2006, 17h11
  2. mot clef sql pour nom de champ
    Par bobinou007 dans le forum Langage SQL
    Réponses: 4
    Dernier message: 12/10/2004, 13h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo