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

Qt Discussion :

QMap : operator< de QPoint


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Par défaut QMap : operator< de QPoint
    Bonjour,

    Je manipule actuellement une QMap avec en clé des QPoint.

    J'ai donc redéfinie notamment la méthode "operator<" appelée au moment des insert dans ma map :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    inline bool operator<(const QPoint &p1, const QPoint &p2)
    {
      return ((p1.x() < p2.x() && p1.y() <= p2.y()) ||
              (p1.x() =< p2.x() && p1.y() < p2.y()));
    }
    Malgré tout, j'observe deux comportements que je n'arrive pas bien à comprendre :

    1) En mode debug, j'observe que l'operator fait appel à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <class Key> inline bool qMapLessThanKey(const Key &key1, const Key &key2)
    {
        return key1 < key2;
    }
    Mais là, bien que key1 vaut bien QPoint(50,22) et key2 QPoint(160,22), il semble que la valeur key1<key2 ne soit pas définie. J'observe après une boucle entre l'operator et le qMapLessThanKey.

    2) Après un premier élément inséré dans la map de clé QPoint(50,22), j'observe que l'insertion d'un autre élément de clé QPoint(160,22) va venir écraser le premier élément (toujours un élément dans la map et la valeur est égale à celle du dernier inséré..)

    Avez-vous une explication ?

    Merci

  2. #2
    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,


    Ta logique ne semble pas en mesure de fournir un "état unique" nécessaire pour l'opérateur <.

    Si l'on réfléchi à la table de vérité, on a:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
             |         |     (1)    |    (2)     |     (3)     |     (4)     |    (5)    |    (6)    |    (7)
     first   | second  |first.x() < |first.y() < | first.x()<= |first.y() <= | (1) && (4)| (3) && (2)| (5) || (6)
    x() |y() |x() |y() |second.x()  |second.y()  |second.x()   |second.y()   |           |           |         
    -----------------------------------------------------------------------------------------------------------------
    10  |10  |15  |15  |true        |true        |true         | true        |   true    |    true   | true ==> ok
    10  |10  |15  |10  |true        |false       |true         | true        |   true    |    false  | true ==> ok
    10  |15  |15  |10  |true        |false       |true         | false       |   false   |    false  | false ==> oops
    15  |10  |15  |15  |false       |true        |true         | true        |   false   |    true   | true ==> ok
    15  |10  |15  |10  |false       |false       |true         | true        |   false   |    false  | false ==> ok
    15  |15  |15  |10  |false       |false       |true         | false       |   false   |    false  | false ==> ok
    15  |10  |10  |15  |false       |true        |false        | true        |   false   |    false  | false ==> ok
    15  |15  |10  |15  |false       |false       |false        | true        |   false   |    false  | false ==> ok
    15  |15  |10  |10  |false       |false       |false        | false       |   false   |    false  | false ==> ok
    Comme tu peux le constater, il y a un moment où la table de vérité nous donne un résultat incohérent: c'est quand le premier point a x == 10 et y == 15 et que le second point a x==15 et y == 10

    On se serait en effet attendu à ce que le résultat vale... true

    Généralement, lorsqu'il s'agit de combiner plusieurs valeurs dans un test "plus petit que", on travaille sur une logique de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    bool operator <(QPoint const & first, QPoint const & second)
    {
        return first.x() <second.x() || 
               ( first.x() == second.x() && first.y() < second.y() ) ;
    }


    NOTA: Personnellement, je ne crois pas que je créerais un opérateur <, mais plutôt un foncteur clairement nommé qui fournisse le résultat.

    On peut en effet discuter le choix de prioriser la valeur de x par rapport à celle de y, et il n'est donc pas impossible que, tôt ou tard, tu veuilles avoir un tri qui donne la priorité à y.

    En définissant l'opérateur < pour l'une des possibilités, tu places une restriction forte en terme d'évolution, que tu pourrais très facilement éviter en utilisant un foncteur
    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
    Membre éclairé
    Avatar de betsprite
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    472
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 472
    Par défaut
    Salut koala01 et merci pour ton aide

    Effectivement, la table de vérité présente des cas non gérés correctement..

    Merci également pour l'idée du foncteur qui semble la plus intéressante en terme d'évolution!

  4. #4
    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
    Citation Envoyé par betsprite Voir le message
    Salut koala01 et merci pour ton aide

    Effectivement, la table de vérité présente des cas non gérés correctement..

    Merci également pour l'idée du foncteur qui semble la plus intéressante en terme d'évolution!
    Avec palisir
    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

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Par défaut
    Bonjour,

    Je me suis intéressé au problème et j'ai essayé de faire quelque chose de similaire. Apparemment, pour profiter d'un foncteur avec QMap, on doit d'abord créer une std::map avec ce foncteur et ensuite la passer au constructeur de la QMap.

    J'ai donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        class Less // foncteur
        {
          public :
            bool operator()(const QPoint& p1, const QPoint& p2)
            {
              return p1.x() < p2.x() ||
                      (p1.x() == p2.x() && p1.y() < p2.y());
            }
        };
    Puis ensuite, dans le constructeur de la class ou j'ai ma QMap :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
          Less lessFunctor;
          std::map<QPoint, Obj, Less> map = std::map<QPoint, Obj, Less>();
          m_map = QMap<QPoint, Obj>(map);
    Mais j'obtiens l'erreur :

    erreur : no matching function for call to 'QMap<QPoint, Obj>::QMap(std::map<QPoint, Obj, Less>&)'
    Je dois mal m'y prendre pour l'utilisation du foncteur j'imagine?
    Après dans les constructeurs proposés par QMap, on a bien un std::map mais seulement avec la clé et la valeur indiquées, pas de foncteurs possibles en troisième argument ?

    Merci

    PS : Obj représente juste un objet dont la connaissance n'est pas utile ici.

  6. #6
    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
    C'est parce que tu t'y prend mal...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
          Less lessFunctor;
          std::map<QPoint, Obj, Less> map; // laisse le constructeur par défaut faire son job ici
          m_map = map; // laisse l'opérateur d'affectation faire son job ici
    En plus, dans le constructeur d'une classe, il est préférable d'utiliser les listes d'initialisation:
    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
    class MaClass : public QWidget{
        public:
            MaClass(QWidget * parent):QWidget(parent){ // m_map est créé automatiquement
                                                       // avec son constructeur par défaut
                /*rien à faire ici */
            }
            /* OU OU OU / ET ET ET */
            MaClass(QWidget * parent, QMap<QPoint, Obj, Less> const & map):
                QWidget(parent), m_map(map){ // m_map est créé en utilisant le 
                                             // constructeur par copie 
                /* rien à faire ici */
            }
        private:
            QMap<QPoint, Obj, Less> m_map;
    };
    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

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

Discussions similaires

  1. operator>> pour une QMap avec qt dbus
    Par bourriquet_42 dans le forum Qt
    Réponses: 1
    Dernier message: 18/02/2009, 17h49
  2. afficher la signature des opérations dans XDE
    Par ChristopheH dans le forum Rational
    Réponses: 1
    Dernier message: 24/05/2004, 15h41
  3. [JSP] thread ? Message d'avancement des operations en cours
    Par buffyann dans le forum Servlets/JSP
    Réponses: 14
    Dernier message: 18/12/2003, 11h39
  4. operation sur des alias
    Par 74160 dans le forum Requêtes
    Réponses: 4
    Dernier message: 24/11/2003, 18h19
  5. Réponses: 8
    Dernier message: 21/11/2003, 18h38

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