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

MFC Discussion :

STL : std::set problème avec insert ...


Sujet :

MFC

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut STL : std::set problème avec insert ...
    Bonjour,

    j'aimerais utilisé std::set, mais j'ai quelques ennuis ...


    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
    // ------
    class SCImports
    {
    public:
       SCImports(const std::string & etat1, const std::string & etat2)
          : nom1(etat1),nom2(etat2)
       {
       }
       std::string nom1;
       std::string nom2;
    };
     
    // ------
    // déclaration dans une autre classe Test
    std::set<SCImports>                 listeSCImports;
     
    // ------
    // utilisation dans cette autre classe Test
     
    ((std::set<SCImports>) listeMaClasse).insert((SCImports)classe);
    Si je compile la classe Test, j'obiens de visual 2002 cette erreur :

    C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\functional(139): error C2676: binary '<' : 'const SCImports' does not define this operator or a conversion to a type acceptable to the predefined operator

    d'où ma question, est-ce que je dois surcharger l'opérateur "<" ?
    Est-ce que ça ne devrait pas plutôt être l'opérateur "==" pour déterminer si la clé (l'élément à insérer) est déjà présent dans la "liste" set ?

    Si je dois surcharger l'opérateur comment je fais avec ma classe qui a seulement 2 string en attribut, et plus intéressant comment je fais si c'est une classe qui a plein d'attributs ?

    Merci de vos réponses, j'espère avoir été clair. Cependant, il se peut que je n'ai pas bien compris le fonctionnement de set (qui pour moi est une sorte de liste de clé donc impossible d'avoir 2 fois la même clé dans set), si c'est le cas merci de me donner d'autres informations...

    En passant, un lien intéressant sur les containers :

    http://www.mines.u-nancy.fr/~tombre/...olyCpp008.html

    Big. K

  2. #2
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2002
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2002
    Messages : 290
    Points : 325
    Points
    325
    Par défaut
    il faut surcharger < ET == ET le constructeur de copie ET l'operateur =

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut Re: STL : std::set problème avec insert ...
    Citation Envoyé par Big K.
    Bonjour,
    C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\functional(139): error C2676: binary '<' : 'const SCImports' does not define this operator or a conversion to a type acceptable to the predefined operator

    d'où ma question, est-ce que je dois surcharger l'opérateur "<" ?
    Est-ce que ça ne devrait pas plutôt être l'opérateur "==" pour déterminer si la clé (l'élément à insérer) est déjà présent dans la "liste" set ?
    Pour utiliser 'set' il faut disposer d'un moyen de comparer deux éléments.
    Il est possible de fournir une telle fonction lors de l'instanciation du template.
    Si aucune fonction de comparaison n'est fournie alors '<' est utilisé par défaut.

    La fonction doit définir une relation d'ordre faible entre les éléments du set.
    Pour plus d'info http://www.sgi.com/tech/stl/set.html
    Le truc à retenir c'est que la comparaison doit être irreflexive. C-à-d que 'compare(a, a)' retourne faux. En gros, ça marche avec '<' ou '>' mais pas avec '<=' ou '>='

    Pour résoudre le problème il y a alors deux façon de faire:
    - surcharger l'opérateur < (pas terrible).
    - définir une fonction de comparaison.

    On peux, par exemple, concaténer les deux chaînes et de les comparer.

    Par exemple
    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
     
    struct SCImportsCompare
    {
      bool operator()(const SCImports& lhs, const SCImports& rhs) const
      {
         string s1(lhs.nom1);
         s1.append(lhs.nom2);
     
         string s2(rhs.nom1);
         s1.append(rhs.nom2);
     
         return ( s1.compare(s2) < 0 );
      }
    };
     
     
    // Création du Set
    set<SCImports, SCImportsCompare> mySet;

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    je viens de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    bool operator < (const SCImports& _Right) const
    {	// apply operator< to operands
             int result = this->nom1.compare(_Right.nom1);
             if (result < 0)
                return true;
             else
                return false;
    }
    et ça compile, seulement ça règle pas mon problème, car à mon avis la clé ne se fait que sur le nom1 !!!

    Sinon pourquoi je devrais surcharger "==", "=" et le constructeur de copie ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Citation Envoyé par Gandalf
    il faut surcharger < ET == ET le constructeur de copie ET l'operateur =
    Je ne vois pas de raison immédiate de définir '==' .

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    Merci VoidSeer, j'aime bien ton idée de concaténer les 2 chaines

    Sinon quand on a une grande classe, il n'y a pas de moyen miracle.
    pffou, heureusement que je n'ai que 2 strings :>

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Citation Envoyé par Big K.
    Merci VoidSeer, j'aime bien ton idée de concaténer les 2 chaines

    Sinon quand on a une grande classe, il n'y a pas de moyen miracle.
    pffou, heureusement que je n'ai que 2 strings :>
    Je ne suis pas sur qu'utiliser un set dans le problème que tu essaie de résoudre une solution adaptée si tu as du mal à définir une comparaison entre eux.

    Si ce que tu souhaite c'est d'avoir une liste d'objet ou une même instance n'apparaît pas plus d'une fois, il serait plus facile de manipuler un set de pointeurs.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    non c juste une liste de string, rien à voir avec les instances ...

    Merci, donc en gros il suffit de faire avec une classe de comparaison et ça compile (on verra à l'exécution !!!), fin ça ne devrait plus me poser de problèmes.

    Donc si jamais j'ai une grande classe, il suffit de comparer chaque attribut entre eux ?

    J'ai un doute sur la concaténation de mes deux chaines ? Est-ce que si je fais ((lhs.nom1 == rhs.nom1) && (lhs.nom2 == rhs.nom2)) ça marche ou non ?

    Désolé, mais chez moi c'est le matin, et je suis pas encore très clair ...

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Citation Envoyé par Big K.
    non c juste une liste de string, rien à voir avec les instances ...
    J'ai un doute sur la concaténation de mes deux chaines ? Est-ce que si je fais ((lhs.nom1 == rhs.nom1) && (lhs.nom2 == rhs.nom2)) ça marche ou non ?
    Non, c'est le point épineux. Set ne veux pas de fonction d'égalité, mais de comparaison.

    <mode matheux on>
    La fonction de comparaison doit avoir les trois propriétés suivante:
    - irreflexivité: compare(a, a) retourne faux !
    - transitivité: si compare(a,b) et compare (b,c) sont vrai alors compare(a,c) doit aussi être vrai.
    - antisymetrique: si compare(a,b) est vrai alors compare(b,a) est nécessairement faux.

    Une relation d'égalité est par nature réflexive et symetrique
    (a == a) et si (a == b) alors (b == a) donc l'égalité ne peut pas servir comme fonction de comparaison dans un set.
    <mode matheux off>

    C'est pour cela que dans mon exemple précédant j'utilise une comparaison stricte entre 0 et la comparaison des deux chaînes de caractères.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    ok, merci pour cette explication, je le sentais bien que c'était une idée bête mon test d'égalité, mais je ne voyais pas pourquoi.

    Merci encore.

  11. #11
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2002
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2002
    Messages : 290
    Points : 325
    Points
    325
    Par défaut
    pourquoi surcharger =, ==, et le constructeur de copie ?
    Parce que c'est, me semble-t-il, la classe cannonique...

    tu risque de recontrer des Pb tant que tu ne les aura pas surchargés...

    Les pires sont les constructeur de copie, et l'operateur d'affectation. Ils peuvent etre généré par le compilo au besoin ! et donc les copies peuvent etre mal faites... Si tu ne veux pas les surcharger, il est bon de les déclarer en private et de ne pas les implementer, ainsi le compilo ne peut plus les generer, et l'utilisation implicite d'un de ces formes provoque une erreur de compil si c'est a l'exterieur de la classe, de link si c'est à l'interieur...

    Quand au == s'il n'est pas surchargé il est alors supposé etre :

    !((a<b)||(b<a))

    ce qui n'est pas toujours ce que l'on souhaite...

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    Bon la méthode de VoidSeer fonctionne parfaitement.
    Sinon j'ai pu me renseigner auprès de quelqu'un qui maitrise le C++ et on peut également définir un opérateur < à la classe SCImports, ensuite on doit juste déclarer le set ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::set<SCImports, std::less<SCImports>>                 listeSCImports;
    et ça fonctionne aussi bien.

    Merci à tous.

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 279
    Points : 11 015
    Points
    11 015
    Par défaut
    Normalement, si tu défini l'opérateur <, inutile de l'expliciter dans la déclaration de l'ensemble. On manipule explicitement le second paramètre, essentiellement si la fonction d'ordre utilisée n'est pas l'opérateur <. C'est ce que disait (implicitement) VoidSeer dans son premier message.

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2003
    Messages : 21
    Points : 17
    Points
    17
    Par défaut
    exact, c'est juste que c'est un peu plus lisible ...

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

Discussions similaires

  1. [Conception] Problème avec INSERT dans une TABLE
    Par dunbar dans le forum PHP & Base de données
    Réponses: 26
    Dernier message: 20/07/2006, 12h56
  2. Problème avec insertion image
    Par technopole dans le forum Tableaux - Graphiques - Images - Flottants
    Réponses: 2
    Dernier message: 26/06/2006, 21h45
  3. [VB6] Problème avec insertion d'icônes dans menu
    Par marsup54 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 02/03/2006, 21h38
  4. Réponses: 12
    Dernier message: 25/11/2005, 12h29
  5. Réponses: 3
    Dernier message: 10/05/2005, 11h02

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