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 :

Que faire contre les 'Parameter type mismatch'es ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut Que faire contre les 'Parameter type mismatch'es ?
    Bonjour,

    Je suis en C++03 et j'ai un code comme ceci :

    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
     
    // Fonctions de la bibliothèque que j'utilise
    virtual uint16_t TextArea::getTextWidth() const;
    virtual void Drawable::setX(int16_t x);
    virtual void Drawable::setWidth(int16_t width;
     
     
    // Creation de mes drawables
    Box background_m;
    TextArea text_m;
     
     
    // Code utilisant tout ce beau monde
    enum
    {
    BACKGROUND_BORDER = 10
    };
     
    int16_t bw = text_m.getTextWidth() + BACKGROUND_BORDER * 2;
    background_m.setX(width / 2 - bw / 2);
    background_m.setWidth(bw);
    Mon IDE CLion analyses le code à la volée (avec clang j'ai l'impression) et me lève un warning comme ceci sur l'appel à setX():
    Warning:(39, 23) Parameter type mismatch: Values of type 'int' may not fit into the receiver type 'int16_t'
    Que faire dans pareil cas ?

    Merci pour vos conseils !

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Salut,

    static_cast
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Clang a raison : tu essayes de faire entrer une valeur de type int (classiquement codé sur 4 bytes) dans une valeur codée sur 2 bytes. Voilà qui pourrait poser bien des problèmes, indépendamment du fait que l'on sait pertinemment bien que BACKGROUND_BORDER est "dans les limites" (une question que je me pose avec ton code: "what if" getTextWidth() venait à renvoyer une valeur égale à std::numeric_limits<int16_t>::max()-5 Tu serais un peu dans la merde, non ).

    L'idéal, bien sur, serait de pouvoir modifier la signature de setWidth pour qu'elle accepte un int (qui devrait d'ailleurs être non signé, au passage), histoire de n'avoir plus de problème à ce sujet ou (mais ce n'est possible qu'en C++11 et ultérieur, donc impossible pour toi) de définir le type de l'énumération comme étant de type int16_t. Mais je me doute bien qu'il n'est pas en ton pouvoir de le faire

    Du coup, la solution de Bousk est bel et bien la seule solution possible : dire à clang que tu sais que les types ne correspondent pas, mais que "tu sais ce que tu fais" (en priant pour que ce soit effectivement le cas, cf la question que je posais plus haut), et qu'il peut sans problème faire la conversion.

    Juste un truc au passage: C++11 est sorti il y a maintenant six ans. C++14 est sorti depuis trois ans, et il est supporté par tous les compilateurs récents. Je me doute bien que tu n'as "pas voix au chapitre" sur ce coup, mais tu n'envisagerais pas de "donner un coup de pied dans la fourmilière" pour inciter les décideurs à mettre leurs outils à jour
    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

  4. #4
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Salut,

    Tu peux convertir tes entiers en int16_t avec boost::numeric_cast :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <boost/numeric/conversion/cast.hpp>
     
    namespace DrawableUtil
    {
        template<class IntegerType>
        void setX(Drawable& drawable, IntegerType x)
        {
            drawable.setX(boost::numeric_cast<int16_t>(x));
        }
    }
    Si l'argument est en dehors des limites de int16_t, cela lancera une exception boost::numeric::positive_overflow ou boost::numeric::negative_overflow.

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    En fait, je n'étais qu'à moitié sérieux quand je posais la question d'un éventuel dépassement de valeur, car, vu que l'on parle d'une fenêtre à l'écran, même en comptant en pixels en HD, on devrait toujours être dans une zone de sécurité à ce sujet.

    Et puis, je suis plutôt d'avis qu'il faudrait une assertion et non une exception pour ce genre de dépassement, car c'est clairement le genre de chose auquel le développeur doit apporter une solution en cas d'erreur
    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

  6. #6
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Et puis, je suis plutôt d'avis qu'il faudrait une assertion et non une exception pour ce genre de dépassement, car c'est clairement le genre de chose auquel le développeur doit apporter une solution en cas d'erreur
    A mon avis, dans la plupart des cas de ce genre, des assertions ne serviraient à rien, à part encombrer le code.
    En effet, admettons que l'on ait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <limits>
     
    namespace DrawableUtil
    {
        template<class IntegerType>
        void setXAvecPrecondition(Drawable& drawable, IntegerType x)
        {
            assert(x >= std::numeric_limits<int16_t>::min());
            assert(x <= std::numeric_limits<int16_t>::max());
            drawable.setX(static_cast<int16_t>(x));
        }
    }
    Si on a des préconditions, c'est pour qu'elles soient contrôlées dans le code appelant.
    Or, que fera le code appelant quand un argument sera trop petit ou trop grand ? Il lancera une exception.
    Comme le code qui lancera cette exception sera toujours le même, il sera factorisé, par exemple comme ceci :
    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
    #include <boost/numeric/conversion/cast.hpp>
    #include <limits>
     
    namespace DrawableUtil
    {
        template<class IntegerType>
        void setXAvecPrecondition(Drawable& drawable, IntegerType x)
        {
            assert(x >= std::numeric_limits<int16_t>::min());
            assert(x <= std::numeric_limits<int16_t>::max());
            drawable.setX(static_cast<int16_t>(x));
        }
     
        template<class IntegerType>
        void setX(Drawable& drawable, IntegerType x)
        {
            static_cast<void>(boost::numeric_cast<int16_t>(x));
            setXAvecPrecondition(drawable, x);
        }
    }
    Le code appelant appellera directement DrawableUtil::setX plutôt que DrawableUtil::setXAvecPrecondition. Ainsi, on reviendra au point de départ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <boost/numeric/conversion/cast.hpp>
     
    namespace DrawableUtil
    {
        template<class IntegerType>
        void setX(Drawable& drawable, IntegerType x)
        {
            drawable.setX(boost::numeric_cast<int16_t>(x));
        }
    }
    On pourrait m'objecter que ce n'est pas DrawableUtil::setX qui devrait lancer l'exception, mais le code appelant, afin que le message de l'exception contienne des informations contextuelles.
    Mais les deux idées sont compatibles. Si on veut concevoir un programme avec une gestion d'erreurs sophistiquée, ce que l'on peut faire, c'est travailler avec des types d'exception sophistiqués qui ont des constructeurs capables de capturer l'état de la pile et des fonctions pour accumuler des informations contextuelles.
    Alors, dans DrawableUtil::setX, on aurait un code du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <limits>
     
    namespace DrawableUtil
    {
        template<class IntegerType>
        void setX(Drawable& drawable, IntegerType x)
        {
            if(x < std::numeric_limits<int16_t>::min())
                throw MaSuperExceptionEntierTropPetit(x, std::numeric_limits<int16_t>::min());
            if(x > std::numeric_limits<int16_t>::max())
                throw MaSuperExceptionEntierTropGrand(x, std::numeric_limits<int16_t>::max());
            drawable.setX(static_cast<int16_t>(x));
        }
    }
    Et, dans le code appelant, on aurait quelque chose du genre :
    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
    try {
        [...]
            // code qui appelle DrawableUtil::setX et d'autres fonctions qui peuvent lever
            // plein de types d'exceptions différents
     
    } catch(MaSuperException& e) { // MaSuperException est une classe de base abstraite.
        e.ajouterInformationContextuelle("blababla");
        throw; // Bonne nouvelle : le type dynamique de l'exception n'est pas perdu.
    } catch(...) {
        std::exception_ptr eptr = std::current_exception();
        const std::string infoContextuelle = "blababla";
        convertirEnMaSuperException_puis_ajouterInformationContextuelle_puis_repropager(eptr, infoContextuelle);
            // La fonction ci-dessus factorise un râteau de catch.
            // Le type dynamique de l'exception MaSuperException propagée dépend du type
            // de l'exception capturée dans eptr.
    }

  7. #7
    Membre actif
    Homme Profil pro
    007
    Inscrit en
    Octobre 2014
    Messages
    119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : 007

    Informations forums :
    Inscription : Octobre 2014
    Messages : 119
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Je suis en C++03 et j'ai un code comme ceci :
    T'es vraiment en C++03 ??? ou C++03TR1 ?
    D'où sort-il ton int16_t ? Tout ça me laisse perplexe. Mon avis est que tu
    compiles déjà, et au minimum, en C++11.

    Essaye de voir ce que ça donne en typant ton énumération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    enum : int16_t {BACKGROUNG_BORDER= 10};
    ou mieux, faire un "#pragma message" sur "__cplusplus".

    +/- HS:
    Un fichier de configuration, pour moi, doit être validé au plus tôt et au court
    du démarrage de l'application. Donc, très en amont. Parce que charger et
    contrôler les données au fur et à mesure des besoins alors que l'application
    est déjà bien avancée dans le "runtime", ça ne laisse présager rien de bon
    pour l'utilisateur final.

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

Discussions similaires

  1. Êtes-vous pour ou contre les "strict type hints" ?
    Par RideKick dans le forum Langage
    Réponses: 44
    Dernier message: 21/03/2012, 21h18
  2. [CS3] Que faire quand les templates ne mettent plus a jour ?
    Par holala! dans le forum Dreamweaver
    Réponses: 1
    Dernier message: 06/05/2008, 07h05
  3. [AJAX] Que faire contre les fuites mémoires (memory leaks)
    Par cassy dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 21/08/2007, 16h50
  4. Que faire lorsque les performances d'une base chute ?
    Par Doctor Z dans le forum Oracle
    Réponses: 11
    Dernier message: 16/02/2005, 14h38

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