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

SL & STL C++ Discussion :

std::pair et reference


Sujet :

SL & STL C++

  1. #1
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut std::pair et reference
    Je souhaiterais que la valeur retour d'une fonction soit une paire comme cecimais ça ne compile pas.
    A l'origine la fonction renvoit une reference seule, mais j'aimerais y ajouter un bool. Comment faire ?
    Merci.

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 11
    Par défaut
    Tu peut passer par un paramettre donnée-résultat. Du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T& fonction(int i, bool& b)

  3. #3
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    le plus simple étant bien souvent le moins compliqué, et un typedef ne pouvant pas être template, je serais toi, je passerais par une petite structure. Un truc dans le style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename T>
    struct boolean_pair
    {
       T & Ref;
       bool Flag;
    };
     
    // et du coup la fonction aura cette tête:
    template <typename T>
    boolean_pair<T> ma_fonction( /* parametres */ );

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Effectivement, la norme indique bien comme constructeur pair(const T1& x, const T2& y), ce qui de facto t'empêche d'avoir T1 ou T2 comme T&...

    Sinon, la solution Rod est la plus simple. Mais généralement, ce genre de cas veut dire : si bool est vrai, alors T est valide et si bool est faux alors T n'est pas valide. Boost offre Boost.Optional pour résoudre ce genre de chose :
    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
     
    template<class T>
    boost::optional<T&> ma_fonction(T&p_)
    {
       //...
       if(ok)
       {
            return boost::optional<T&>(p_);
       }
       return boost::optional<T&)();
    }
     
    // utilisation :
    boost::optional<T&> ret = ma_fonction(param);
    if(ret){// ok!
       T&resultat = *ret;
    }
    else{//ko
    }

  5. #5
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Dans mon cas bool==true veut dire "T & est nouveau", bool==false veut dire "T & existe déjà" (un peu comme map::insert()).

    Sinon, ce petit débat pour tester la valeur retour d'une fonction est intéressant. J'ai lu il n'y a pas très longtemps "les solutions les plus simples sont les moins compliquées" () et le plus simple est de renvoyer un... pointeur. S'il est nul la valeur est invalide.
    Il m'est d'ailleurs déjà arrivé de faire la même chose avec des références pour lesquelles il suffit de tester leur adresse:
    T & ref=foo();
    if (&ref) valide; else invalide;

    mais ce n'est pas très sécurisant je le reconnais.

    Il semble que boost::optional conceptualize cet aspect des choses. Mais s'il ne fait "que" ça, c'est un peu lourd quand même...
    Je sais que beaucoup ici n'aime pas les pointeurs et cherche à tout prix à les cacher, mais le pointeur reste une base incontournable du C++ (abondamment utilisé il me semble dans la STL, boost, etc).

    Pour en revenir à mon petit soucis de conception, je pense que la solution de r0d semble la plus élégante.
    Concrêtement je suis en train d'écrire un cache template basique. Lorsque l'on requiert une entrée du cache via une clé on a besoin de savoir si l'entrée est nouvelle ou si elle existe déjà. Il me reste un autre petit soucis, comment faire savoir à l'appelant qu'une entrée du cache va être supprimée (je pense à un callback, un peu comme un prédicat).

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par camboui Voir le message
    Il semble que boost::optional conceptualize cet aspect des choses. Mais s'il ne fait "que" ça, c'est un peu lourd quand même...
    Ca veut dire quoi lourd ? Le bout de code que j'ai mis en exemple me semble pourtant 'simple', non?

    Citation Envoyé par camboui Voir le message
    Je sais que beaucoup ici n'aime pas les pointeurs et cherche à tout prix à les cacher, mais le pointeur reste une base incontournable du C++ (abondamment utilisé il me semble dans la STL, boost, etc).
    Et une base incontournable de la plus part des bugs

    Citation Envoyé par camboui Voir le message
    Pour en revenir à mon petit soucis de conception, je pense que la solution de r0d semble la plus élégante.
    Sans boost, c'est surtout la plus simple.

    Citation Envoyé par camboui Voir le message
    Concrêtement je suis en train d'écrire un cache template basique. Lorsque l'on requiert une entrée du cache via une clé on a besoin de savoir si l'entrée est nouvelle ou si elle existe déjà. Il me reste un autre petit soucis, comment faire savoir à l'appelant qu'une entrée du cache va être supprimée (je pense à un callback, un peu comme un prédicat).
    Bizarre. J'aurais tendance à penser que le cache est celui qui sert l'objet, donc il sait s'il peut le fournir tout de suite ou s'il doit aller le chercher. Peux-tu préciser ta conception ?
    [EDIT]: ou au - celui qui sert l'objet a le cache et l'interroge pour savoir s'il contient l'objet, sinon, il va le lire et le rajoute au cache.

  7. #7
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    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
    template <typename K, typename T>
    class cache
    {
    	...
     
    public:
    	struct cell_value
    	{
    		T & s_value;
    		bool s_created;
     
    		cell_value(T & value,bool created):s_value(value),s_created(created) {}
    		cell_value(cell_value const & r):s_value(r.s_value),s_created(r.s_created) {}
    		cell_value & operator=(cell_value const & r)
    			{ s_value=r.s_value;s_created=r.s_created;return *this; }
    	};
     
    	cache(unsigned maxCell);
    	~cache() { clear(); }
     
    	void clear();
     
    	void reset(unsigned maxCell);
     
    	cell_value fetch(K key);
    };
    La méthode fetch() renvoit l'entrée dans le cache correspondant à une clé, en plus d'un booléen pour savoir si l'entrée est créée ou si elle existait déjà. Reste que si l'entrée lru a été rétirée, on ne le sait pas (encore).

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par camboui Voir le message
    Reste que si l'entrée lu a été retirée, on ne le sait pas (encore).
    C'est ce que je n'arrive pas à comprendre. Quelle est la responsabilité de ton cache ? Et celle de celui qui l'utilise ?

  9. #9
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    L'entrée LRU (la plus vieille quoi).

    Le cache est une collection de cellules en nombre limité. Ces cellules contiennent une clé K et une tampon T.
    L'utilisateur demande au cache de lui fournir un tampon T pour une clé K donnée. Le cache ne refuse jamais, il renvoit pour cela une référence sur ce tampon T correspondant à la clé K, et un booléen pour informer si ce tampon vient d'être créé ou s'il existait.
    Comme le cache possède un nombre limité de cellules et qu'il ne refuse jamais une nouvelle cellule, il se peut qu'il doive en supprimer une, à priori la plus ancienne (il peut y avoir d'autres stratégies). C'est cette cellule éventuellement supprimée qui doit pouvoir être notifiée à l'utilisateur via un "callback" juste avant sa suppression effective du cache (et donc avant le retour de la fonction fetch).

    Il suffirait de rajouter une méthode qui teste une clé et qui renvoit une référence sur le tampon qui serait supprimé le cas échéant. Mais je préfère une solution avec "callback" (un peu à la manière des prédicats de la STL). Elle permet d'éviter de rechercher deux fois la clé, une fois lors du test, une deuxième fois lors du fetch().

    En bref, le rôle de l'utilisateur consiste simplement à appeler la méthode fetch() pour récupérer le tampon dans le cache correspondant à sa clé: il initialise ce tampon s'il vient d'être créé, il l'utilise sinon. Rien de plus, l'info se trouvant dans la valeur retour de fetch() (<T&,bool>).
    Mais parfois (et pas toujours), l'utilisateur a besoin de savoir si le cache a dû faire de la place.

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Ok, compris.

  11. #11
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Je recopie un extrait de mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	struct cell_value
    	{
    		T & s_value;
    		bool s_created;
     
    		cell_value(T & value,bool created):s_value(value),s_created(created) {}
    		cell_value(cell_value const & r):s_value(r.s_value),s_created(r.s_created) {}
    		cell_value & operator=(cell_value const & r)
    			{ s_value=r.s_value;s_created=r.s_created;return *this; }
    	};
    Il y a quelque chose qui ne va pas, l'operator= d'assignation est incorrect.

    En fait il est impossible de changer une référence.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int i=3;
    int & rint=i;
    int j=2;
    rint=j;//rint ne prend pas une référence sur j,
    // mais modifie i avec la valeur de j !!!
    Du coup la solution proposée par r0d ne convient pas ?

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Tu vas devoir passer par boost::optional ...

  13. #13
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Bah, non
    Je supprime l'assignation pour forcer la création d'une variable locale, comme pour toute référence. Et ce n'est pas plus mal finalement.

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Je regarde ta classe et je ne comprend pas pourquoi tu redéfinis le constructeur par copie et l'opérateur d'assignation. La version générée par le compilateur par défaut devrait te suffire non?

  15. #15
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Oui, j'essaie ça.
    Mais j'ai encore quelques soucis à propos des "big fours", je ne sais jamais trop quel est le comportement par défaut...
    Faudra que j'ouvre une discussion à ce propos un de ces quatre

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Je dirais que tant que ça consiste à faire une bête recopie de tes attributs, ben le fait pas. Comme le destructeur :si vide et pas d'héritage, ben pas de destructeur.

  17. #17
    screetch
    Invité(e)
    Par défaut
    Les destructeurs, memes vides, c'est pratique pour mettre des points d'arret.

  18. #18
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Tu ne peux pas mettre de référence dans un tuple ou dans un container.
    Il faut donc utiliser boost::reference_wrapper à la place, ou accessoirement un pointeur.

Discussions similaires

  1. Foncteur d'additionnement de std::pair
    Par Fr3ak dans le forum C++
    Réponses: 2
    Dernier message: 24/09/2011, 21h17
  2. [C++0x] std::move(), rvalue reference et comparses
    Par Emmanuel Deloget dans le forum C++
    Réponses: 15
    Dernier message: 07/12/2010, 10h04
  3. Défénir un std::map à partir d'un std::pair
    Par mat087 dans le forum SL & STL
    Réponses: 3
    Dernier message: 30/12/2006, 19h36
  4. tri sur std::vector<std::pair<int, float> >
    Par b4u dans le forum SL & STL
    Réponses: 15
    Dernier message: 01/10/2006, 09h19
  5. Equivalent de std::pair mais pour trois valeurs
    Par Rodrigue dans le forum SL & STL
    Réponses: 6
    Dernier message: 26/09/2006, 22h00

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