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 :

value_type vs make_pair


Sujet :

Langage C++

  1. #1
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut value_type vs make_pair
    [cross-post sur fr.comp.lang.c++]
    Bonjour,
    suite à une discussion sur map::insert et de l'utilisation de map<>::value_type ou de std::make_pair, j'ai n'ai pas réussi à faire un exemple ou std::make_pair fonctionnerait alors que value_type ne fonctionnerait pas (gcc ou VS)

    J'avais souvenir d'un problème de conversion implicite (Josuttis en parle dans The C++ Standard Library 2nd Ed, page 341), constaté à l'époque sur aCC (hpux), notamment avec les std::string et const char*

    Aujourd'hui, je n'arrive pas à retrouver ce problème avec ni gcc 4.8 ni vs2012.

    Du coup, je n'ai pas d'argument technique (vu que je n'arrive pas à le reproduire) pour préférer std::make_pair...
    Il reste, que c'est toujours plus court à taper, et moins à du renommage sur le typedef par exemple.

    Quand est-il au niveau de la norme ?

    Voici mon exemple qui fonctionne... (avec le explicit ni la forme value_type ni la forme make_pair fonctionne)
    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
     
    #include <map>
    #include <string>
    #include <utility>
     
    using namespace std;
     
    struct MyInt {
       /* explicit */ MyInt(int s) : i(s) {}
       int i;
    };
     
    inline
    bool operator<(const MyInt& lhs, const MyInt& rhs) {
       return lhs.i < rhs.i;
    }
     
    int main() {
       typedef map<MyInt, std::string> Ints;
       Ints ints;
     
       ints.insert(Ints::value_type(2, "aCString"));
       ints.insert(make_pair(2, "aCString"));
    }
    edit:
    en C++11,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
       ints.insert({2, "aCString"});
       ints.emplace(2, "aCString");
    sont à priori des alternatives plus intéressantes (plus courtes, moins sensibles au renommage, moins de copie/move pour emplace)

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Et si tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ints.insert(Ints::value_type(2.0f, "aCString"));
    que se passe-t-il ?

  3. #3
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    VS 2012 émet un warning sur la conversion float to int (que ce soit pour le valeur_type ou le make_pair)
    gcc 4.8.1 ne dit rien en -Wall ni pour l'un ni pour l'autre.

    edit : précision version gcc

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Je ne comprend pas trop le commentaire de Josuttis : "To avoid implicit type conversion...".

    Si value_type est bien un std::pair, il faudrait pour cela que son constructeur soit explicite, et pour que son propos soit cohérent, il faudrait que std::make_pair fasse une conversion explicite avant d'appeler le contructeur de std::pair.

    Il faudrait vérifier que ça soit bien le cas, et éventuellement consulter la norme...

  5. #5
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    En effet, je n'ai pas réussi à comprendre le point expliqué dans le livre.
    Dans mon exemple, j'ai un explicit en commentaire mais les 2 cas ne compilent plus.

    Il y a peu de chance que j'arrive à trouver l'information dans la norme...

  6. #6
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Avec make_pair tu vas laisser le compilateur déduire les types, tu vas donc récupérer un pair<T1,T2> que tu vas construire un pair<U1,U2>, ceci interdit les conversion implicite de T1 à U1 et T2 à U2. Dans le cas de la construction directe d'un pair<U1,U2> à partir d'un T1 et T2, ça sera valide dès que tes objets si ces deux objets sont "bindables" aux référence const U1& et const U2& (et constructibles par copie).

    Quelque chose dans ce goût là :
    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
     
    #include<utility>
     
    struct U;
     
    struct T
    {
        T(){}
        explicit T(const T&){}
    };
     
    struct U : T
    {
        U(){}
    };
     
    typedef
        std::pair<T,T>
        pair_type;
     
    void foo(const pair_type&)
    { }
     
    int main()
    {
        foo(pair_type(U(),U()));         //OK
        foo(std::make_pair(U(),U())); //Not OK
    }
    Cependant je n'ai pas trouvé de situation plus idiomatique que celle-ci.

  7. #7
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    C'est un peu loin de l'utilisation d'une map mais j'ai un cas concret qui ne fonctionne pas.

    j'ai fait un exemple avec une std::map<int, std::reference_wrapper<T>> m,
    avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m.insert(std::make_pair(2, std::ref(u)));
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m.insert(value_type(2, u));
    On voit bien avec le std::ref obligatoire, la différence.
    A terme, map.emplace devrait remplacer tout ça de toute façon.

    Merci pour cette exemple

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