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 :

Itérateur : Abstraction du type de la collection


Sujet :

SL & STL C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut Itérateur : Abstraction du type de la collection
    Salut à tous, développeurs noctambules ! (oui, 22h30 c'est tard pour programmer)

    Admettons que j'ai une classe Directory, qui est une collection d'objets de type File.
    Je fais le choix de stocker mes Files dans une liste chainée (ça pourrait être plus judicieux, mais là n'est pas la question).
    Une classe client va donc parcourir la collection avec un code qui ressemble à ceci (je vous apprends rien) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Directory dir;
    list<File*> files = dir.GetFiles();
    for(list<File*>::iterator it = files.begin(); it != files.end(); it++)
    {
      //bla bla bla
    }
    Ça marche très bien, là n'est pas le problème. Mais de toute évidence, ce code montre que l'implémentation de Directory est insuffisamment encapsulée (on voit quel type de collection est utilisé). Et comme chacun sait, ne pas encapsuler correctement, c'est mal.


    Je m'attèle donc à utiliser un type d'itérateur générique. Je m'aperçois qu'il existe un header <iterator> dans la STL et décide donc d'explorer tout cela pour voir quel type serait le plus adapté.
    Attention, à partir de ce point, ça devient hautement expérimental.
    Je tente de modifier la méthode GetFiles().
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    iterator<bidirectional_iterator_tag, File*> Directory::GetFiles()
    {
      //je sais pas encore quoi
    }
    De cette façon, l'implémentation est bien encapsulée.
    Sauf que je ne sais pas comment aller au bout de cette idée.


    Comment faire pour encapsuler le type de la collection ?

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Tu dois pouvoir aussi affecter une interface de conteneur à la classe Directory:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Directory
    {
    public:    
        typedef std::list<file>::iterator iterator;
        iterator begin() { return m_files.begin(); }
        iterator end() { return m_files.end(); }
        // idem versions const ?
     
        ...
     
    private:
        std::list<file> m_files;
    };
    Puis l'utiliser comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Directory dir;
    for (Directory::iterator i = dir.begin(); i != dir.end(); ++i)
    {
        ...
    }
    Mais bon, c'est pas tout-à-fait la même fonctionnalité.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    J'avais déjà testé une solution à base de typedef, mais étrangement je me rappelle pas avoir obtenu une syntaxe aussi limpide que celle que tu me présentes là… ce qui est un bon point
    Bon, par contre, avec cette solution, comment je fais si je veux utiliser un const_iterator ? Ou un reverse_iterator, ou tous les autres ?

    Ils doivent bien servir à quelque chose ces foutus types iterator et iterator_*_tag !

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Bon, par contre, avec cette solution, comment je fais si je veux utiliser un const_iterator ? Ou un reverse_iterator, ou tous les autres ?
    Et bien tu te fais couler un café et tu rajoutes autant de typedefs et de méthodes que nécessaire pour que l'interface de conteneur soit la plus complète possible ! Sans oublier les value_type, reference, const_reference, size_type, difference_type, etc. Et même les size(), empty(), operators et autres .

    Bon, c'est vrai que les iterator_traits/tags, j'ai jamais essayé ... Je me disais que c'était plutôt fait pour implémenter des itérateurs ayant des fonctionnalités propres en plus de celles des conteneurs STL fournis avec le standard.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Je n'ai aucune connaissance dans les concepts de traits et de tags (?) en C++. Je ferais mieux de me renseigner à ce propos.

    Ceci dit, ce problème serait une bonne application de ces notions, et j'encourage les experts en la matière à me donner un coup de main

    Merci à toi, Biozic !

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Les iterator_ags sont là pour pallier une déficience du C++ actuel (les concepts en c++0x devraient simplifier et clarifier ça). Imaginons un algorithme templatisé par un itérateur, qui puisse s'implémenter de deux façon, selon que l'itérateur est à accès aléatoire ou seulement un forward iterator. Il faudrait pouvoir surcharger cet algorithme en fonction de la catégorie d'itérateur à laquelle appartient l'itérateur.

    Or, il est uniquement possible de surcharger en fonction d'un type. L'astuce consiste donc à ce que la personne qui défini un itérateur lui associe un type, conventionnel, qui puisse permettre à l'algorithme de s'y retrouver. Ce sont les
    iterator_tags, un iterator_trait permettant de regrouper cette info et d'autres du même genre.

    Et comme c'est lourd à définir ça, il y a une méthode pour associer tous les types liés à une catégorie en faisant dériver un itérateur perso d'une classe de base.

    Donc, en gros, si on défini son itérateur perso, sans le faire dériver de la classe de base qui va bien, si définir la classe de traits associée, il y a de bonne chances pour qu'on ne puisse pas l'utiliser avec les algorithmes. Réciproquement, si on veut implémenter un algorithme efficacement, utiliser les iterator_tags peut y aider.

    Pour ta question initiale, j'attends aussi une autre fonctionnalité du C++0x, qui permettra d'écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Directory dir;
    auto files = dir.GetFiles();
    for(auto it = files.begin(); it != files.end(); it++)
    {
      //bla bla bla
    }
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Oui, il me semble même que la nouvelle version du langage sera agrémentée d'une boucle foreach. Mais ça ne résout pas le problème, l'interface encapsule toujours partiellement l'implémentation de Directory (à moins que dans l'exemple que tu aies donné, GetFiles() et files.begin() renvoient auto d'après leur définition elle-même, mais je ne pense pas, non ?).

    Sinon, je dois dire que j'éprouve quelques difficultés à comprendre l'intégralité de ton message (c'est certainement bien expliqué, bien qu'un poil abstrait, mais il me manque quelques notions).
    Je vais quand même essayer, tu me dis si j'ai bon ?

    Les iterator_ags sont là pour pallier une déficience du C++ actuel (les concepts en c++0x devraient simplifier et clarifier ça). Imaginons un algorithme templatisé par un itérateur, qui puisse s'implémenter de deux façon, selon que l'itérateur est à accès aléatoire ou seulement un forward iterator.
    Donc là, on a une fonction (libre), définie dans la STL, qu'on va appeler algo(). Cette fonction algo() est templatée et se spécialise de 2 façons différentes, selon si l'itérateur (qui est le paramètre du template) est de type random_iterator ou forward_iterator.
    C'est ça ?
    Il faudrait pouvoir surcharger cet algorithme en fonction de la catégorie d'itérateur à laquelle appartient l'itérateur.
    Là par contre, je vois pas…
    À partir de là, du coup, je ne sais pas trop comment interpréter la suite !


    Réciproquement, si on veut implémenter un algorithme efficacement, utiliser les iterator_tags peut y aider.
    Aurais-tu un exemple de code qui ferait ça, ou un lien vers un cours qui pourrait m'aider à arriver à un code qui le ferait ?


    Au final, je fais bien de persévérer à comprendre, ou bien est-ce que l'encapsulation totale du type d'une collection n'est-il qu'un doux rêve ?

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par three minute hero Voir le message
    Là par contre, je vois pas…
    À partir de là, du coup, je ne sais pas trop comment interpréter la suite !
    Peut-être l'exemple dans http://www.sgi.com/tech/stl/iterator_category.html t'éclairera-t-il ?

    Citation Envoyé par three minute hero Voir le message
    Au final, je fais bien de persévérer à comprendre, ou bien est-ce que l'encapsulation totale du type d'une collection n'est-il qu'un doux rêve ?
    Je pense qu'en fait, dans une certaine mesure, ces iterator_tags ont pour but de désencapsuler les collections. Je m'explique (ou du moins le tente) :
    Encapsuler, ce n'est rien d'autre que de donner une interface unique quelle que soit l'implémentation derrière. En POO en C++, cette interface est explicite (c'est la classe de base). Pour utiliser cette encapsulation, on passe par la manipulation de pointeurs.

    En programmation générique en C++, l'interface est (pour l'instant) implicite. Elle se défini à base de convention de nommage et de documentation. Pour utiliser l'abstraction, on passe par l'intermédiaire de templates. Qu'importe comment elle est implémenté, une classe définissant un opérateur++ et un opérateur* est un itérateur. Elle peut être utilisé par n'importe quel algorithme travaillant avec des itérateurs.

    Finalement, c'est la solution qui t'a été proposée : Définir des typedef avec les noms conventionnel, des fonctions avec des noms conventionnels,... et hop, ton conteneur peut se faire passer pour un autre, il est, du point de vue générique, encapsulé.

    Maintenant, le problème de toute abstraction, c'est qu'elle a un coût. Parfois acceptable, parfois pas. Finalement, les iterator_tags sont un moyen de casser l'encapsulation, et de partir d'un algorithme marchant avec tout pour obtenir un algorithme marchant vite avec les itérateurs qui permettent de faire les choses plus vite (c'est à dire qui offrent une interface plus riche). C'est un peu le dynamic_cast du monde générique.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Très bien, merci pour toutes ces explications !

    Je pense que je vais m'en tenir aux typedef dans un premier temps. Je lirai l'article que tu m'as donné plus tard.

    Bref, un grand merci à vous deux !
    Je passe en résolu.

  10. #10
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Juste un petit message pour te donner un lien vers mon tutoriel sur les classes de traits et de politiques en C++.

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Magnifique, merci Alp !

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Petit épilogue, pour ceux que ça intéresserait.

    Voici comment j'ai implémenté mon itérateur, façon « typedef ».
    Il s'agit en réalité de chanson et de ses pistes (au lieu de dossier et de fichiers), mais l'idée est là.

    EDIT : La solution du post suivant est beaucoup plus simple.

    C'est une classe interne Tracks qui contient une liste de Track*. C'est cette même sous-classe qui déclare les typedef.
    Code Song.h : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    #ifndef _SONG_H
    #define _SONG_H
     
    #include <list>
    using namespace std;
     
    class Track;
     
    class Song
    {
        public:
            class Tracks
            {
                public:
                    typedef std::list<Track*>::iterator iterator;
                    typedef std::list<Track*>::const_iterator const_iterator;
     
        		Song::Tracks::iterator begin();
        		Song::Tracks::const_iterator begin() const;
        		Song::Tracks::iterator end();
        		Song::Tracks::const_iterator end() const;
        		void push_back(Track * track);
        		void remove(Track * track);
     
                private:
                    list<Track *> tracks;
            };
     
    	void Add(Track & track);
    	void Remove(Track & track);
    	const Tracks & GetTracks() const;
     
        private:
    	Tracks tracks;
    };
     
    #endif

    Code Song.cpp : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    #include "Song.h"
    #include "Track.h"
     
    Song::Tracks::iterator Song::Tracks::begin()
    {
    	return tracks.begin();
    }
     
    Song::Tracks::const_iterator Song::Tracks::begin() const
    {
    	return tracks.begin();
    }
     
    Song::Tracks::iterator Song::Tracks::end()
    {
    	return tracks.end();
    }
     
    Song::Tracks::const_iterator Song::Tracks::end() const
    {
    	return tracks.end();
    }
     
    void Song::Tracks::push_back(Track * track)
    {
            tracks.push_back(track);
    }
     
    void Song::Tracks::remove(Track * track)
    {
    	tracks.remove(track);
    }
     
    void Song::Add(Track & track)
    {
    	tracks.push_back(&track);
    }
     
    void Song::Remove(Track & track)
    {
    	tracks.remove(&track);
    }
     
    const Song::Tracks & Song::GetTracks() const
    {
    	return tracks;
    }

    Et ça se parcourt comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for(Song::Tracks::const_iterator trackIt = song.GetTracks().begin(); trackIt != song.GetTracks().end(); trackIt++)
    {
    	//...
    }

    Je voudrais mettre en avant une fonctionnalité du C++ (que je ne connaissais pas). C'est le fait qu'on puisse surcharger une méthode (ici begin() et end()) selon si elle est const ou pas.
    C'est ce qui me permet ici de renvoyer, en fonction du type de tracks (« Tracks » ou « const Tracks ») un « iterator » ou un « const_iterator ». Si GetTracks() avait renvoyé un Tracks non-const, il m'aurait suffit de changer const_iterator en iterator, sans rien toucher d'autre. Bref, c'est magnifique.

    J'ai tenté ça au pif, me sentant bloqué. Je peux vous dire que quand j'ai vu que ça a marché, ça m'a plutôt troué le cul ! Je pensais qu'on ne pouvait surcharger qu'en ne modifiant la liste des arguments.

    J'aime le C++

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Damn, j'ai trouvé vachement plus simple !

    Code Song.h : 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
     
    #ifndef _SONG_H
    #define _SONG_H
     
    #include <list>
    using namespace std;
     
    class Track;
     
    class Song
    {
    	public:
    		typedef list<Track*> Tracks;
    		void Add(Track & track);
    		void Remove(Track & track);
    		const Tracks & GetTracks() const;
     
    	private:
    		Tracks tracks;
    };
    #endif

    Code Song.cpp : 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 "Song.h"
    #include "Track.h"
     
    typedef list<Track*> Tracks;
     
    void Song::Add(Track & track)
    {
    	tracks.push_back(&track);
    }
     
    void Song::Remove(Track & track)
    {
    	tracks.remove(&track);
    }
     
    const Tracks & Song::GetTracks() const
    {
    	return tracks;
    }

    Et ça se parcourt exactement de la même façon.

  14. #14
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Citation Envoyé par three minute hero Voir le message
    EDIT : La solution du post suivant est beaucoup plus simple.[/COLOR]

    Damn, j'ai trouvé vachement plus simple !
    C'était la première version qui était sur-compliquée...

    Au passage, tu n'as pas besoin du typedef de ton .cpp. Il suffit de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const Song::Tracks & Song::GetTracks() const
    {
    	return tracks;
    }
    Mais du coup tu tournes en rond côté encapsulation, en exposant ta liste, non?

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Citation Envoyé par Biozic Voir le message
    C'était la première version qui était sur-compliquée...
    Certes

    Citation Envoyé par Biozic Voir le message
    Au passage, tu n'as pas besoin du typedef de ton .cpp. Il suffit de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const Song::Tracks & Song::GetTracks() const
    {
    	return tracks;
    }
    Ah oui, bien vu

    Citation Envoyé par Biozic Voir le message
    Mais du coup tu tournes en rond côté encapsulation, en exposant ta liste, non?
    En quoi est-ce que j'expose ma liste ? Parce que le typedef est public ?
    C'est une encapsulation insuffisante, d'après toi ?
    Le code du client ne fait pas figurer le mot list !

  16. #16
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Citation Envoyé par three minute hero Voir le message
    En quoi est-ce que j'expose ma liste ? Parce que le typedef est public ?
    C'est une encapsulation insuffisante, d'après toi ?
    Le code du client ne fait pas figurer le mot list !
    C'est sur que tu as l'avantage que le client n'a pas besoin de savoir que c'est une list, il suffit qu'il utilise le typedef.
    En ce qui concerne l'encapsulation, c'est peut-être une question de définition, et je ne suis pas expert. Je dirais que ta list est bien protégée (par la référence constante) mais pas encapsulée , juste histoire de pinailler .

  17. #17
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Hé bien si on veut intéragir dessus comme il se doit, on doit récupérer la liste elle-même.
    Le mieux serait quand même d'offrir une interface utilisable, directement ...

  18. #18
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Voilà les seules deux solutions que j'ai pu trouver !
    Certes, un typedef n'encapsule pas strictement, mais l'important pour moi c'est que si j'ai envie de passer d'une list à un set ou un vector, je ne change pas le code des classes clients !
    N'est-ce pas là la seule chose qui compte ?

    Si vous avez une autre solution, je suis ouvert pour qu'on en discute ensemble .
    Dans un premier temps je me contente de ça… c'est pas en faisant du refactoring que je vais faire avancer mon projet

  19. #19
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 142
    Par défaut
    Citation Envoyé par Alp Voir le message
    Hé bien si on veut intéragir dessus comme il se doit, on doit récupérer la liste elle-même.
    Le mieux serait quand même d'offrir une interface utilisable, directement ...
    En fait, qu'est-ce que cette solution ne permet pas ?

  20. #20
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    rajouter des méthodes begin, end (rbegin, rend) ne serait pas de trop, comme ça ils peuvent parcourir plus facilement, tes objets clients (++, --, ...)

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Unknown abstract schema type
    Par ekremyilmaz dans le forum JPA
    Réponses: 6
    Dernier message: 10/03/2009, 21h01
  2. créer un objet à partir du type d'une collection
    Par dams78 dans le forum Collection et Stream
    Réponses: 11
    Dernier message: 03/11/2008, 14h08
  3. Réponses: 1
    Dernier message: 07/10/2008, 15h49
  4. type variable item collection
    Par samtheh dans le forum VBA Access
    Réponses: 10
    Dernier message: 31/05/2007, 13h31

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