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

C++ Discussion :

Conteneur et habitudes


Sujet :

C++

  1. #21
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Elle apporte par rapport à une fonction prenant un paramètre en référence :
    - Une sémantique claire et non ambiguë.
    À ce propos, y a-t-il des plans dans les prochaines évolutions c++ pour rajouter les paramètres « out » (façon c# ou ada) ?

    C’est à mon sens un manque (et serait une solution simple au problème posé ici).

  2. #22
    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 705
    Points
    2 705
    Par défaut
    Quand on a un seul paramètre à renvoyer, à la lecture du code, utiliser une valeur de retour me semble plus simple.

  3. #23
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Là par contre, ça commence à faire une sacrée différence
    A cause d'une copie inutile de recup vers all. En le déplaçant les timings devraient être beaucoup plus proches.:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::vector<std::string> recup(getList());
    std::move(recup.begin(), recup.end(), std::back_inserter(all));
    Pour ce qui est de la question initiale, je pense que la majorité des codeurs C++ utiliseraient la 1ère méthode, celle avec la référence qui me semble être un bon compromis perf/facilité d'utilisation/lisibilité et qui permet surtout de renvoyer un code d'erreur ou un booléen si le besoin se fait sentir.

  4. #24
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par phi1981 Voir le message
    Toutefois, un point avancé par Koala me parait curieux :

    En fait, si un tel objet FileHolder qui retourne une paire d'itérateurs était à ma disposition, je ne prendrais pas le temps d'implémenter une fonction GetPhotoList(), qui limite forcément les possibilités. Je laisserais l'appelant se débrouiller avec l'objet FileHolder directement, ça lui permettrait de copier la collection vers le conteneur de son choix, ou même d'effectuer certains traitements directement depuis le FileHolder.
    Ne t'attardes peut être pas trop sur la manière dont j'ai utilisé FileHolder, qui n'était qu'un exemple, d'ailleurs sans doute mal choisi au demeurant (surement mal choisi, à lire ta réaction )

    Ce qui importe, c'est surtout d'arriver à utiliser une abstraction capable de représenter "n'importe quel système de fichiers".

    Qu'il s'agisse d'un serveur, d'une tablette, d'un GSM, d'un GPS ou du troisième sous répertoire du disque E de ton pc, c'est le même combat et tu devrais pouvoir utiliser la même abstraction : tu as un dossier, composé sans doute de répertoires et de fichiers, dont tu peux récupérer le nom et d'autres informations (comme la date et l'heure de la création, la date et l'heure de la dernière modification, les droits pour différents types de personnes, ...) qui te permet de travailler "de la même manière, quelles que soient les conditions de travail".

    Je penses, par exemple, à quelque chose comme boost.filesystem qui présente ce genre d'abstraction et qui fonctionne avec n'importe quel système de fichier concret.

    La manière d'utiliser une telle abstraction dépend évidemment très largement de l'interface publique quelle présente, et c'est à toi d'en tenir compte
    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. #25
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    À ce propos, y a-t-il des plans dans les prochaines évolutions c++ pour rajouter les paramètres « out » (façon c# ou ada) ?
    Je n'ai rien vu dans ce sens. Le plus proche que je connaisse est le retour d'un tuple, éventuellement wrappée par l'utilisation de [boost/std]::tie.
    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.

  6. #26
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Arzar Voir le message
    A cause d'une copie inutile de recup vers all. En le déplaçant les timings devraient être beaucoup plus proches.:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::vector<std::string> recup(getList());
    std::move(recup.begin(), recup.end(), std::back_inserter(all));
    Bien vu,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    getAll: 13.3958s
    getAllMove: 15.4859s

  7. #27
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ne t'attardes peut être pas trop sur la manière dont j'ai utilisé FileHolder, qui n'était qu'un exemple, d'ailleurs sans doute mal choisi au demeurant (surement mal choisi, à lire ta réaction )

    Ce qui importe, c'est surtout d'arriver à utiliser une abstraction capable de représenter "n'importe quel système de fichiers".
    Oui ok j'aurais dû arriver à cette conclusion vu que la classe de l'objet est "FileHolder" et non pas un truc genre "PhotoExtractor". Désolé

    Bon j'ai collecté assez d'exemples pour réfléchir tranquillement à mes histoires de conteneurs. Merci beaucoup tout le monde !

  8. #28
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par phi1981 Voir le message
    Oui ok j'aurais dû arriver à cette conclusion vu que la classe de l'objet est "FileHolder" et non pas un truc genre "PhotoExtractor". Désolé
    Allez, je propose donc un très diplomatique "tords partagés" sur ce coup là
    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

  9. #29
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    +1 avec la réponse de Loic:
    De mon point de vue, et à moins d'en savoir plus sur la manière d'utiliser la fonction (et de se rendre compte que le pattern d'utilisation va à l'encontre de l'interface), je partirais en C++11 vers le plus simple : Une fonction qui retourne un vector.
    Personnellement j'utilise quasiment toujours cette version puisque en tant qu'utilisateur de la classe j'attends avec un nom comme getPhotoList de pouvoir écrire un truc comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for(auto const& photo : getPhotoList())
    { 
    //traitement sur la photo de la collection
    }
    Alors que la version en passant la collection en paramètre laisse plein d'inconnues: est-ce que le conteneur doit avoir préalloué la mémoire pour les futurs éléments?, est-ce qu'ils seront ajoutés à la fin?, est-ce que le conteneur sera réinitialisé?, ... Tant de question sans réponse (à moins d'aller lire la doc, ce qui est une bonne pratique, mais je préfère une version plus "intuitive" qui évite les quiproquo)

    PS: en pratique j'utilise une version renvoyant un range avec un typedef sur le range

  10. #30
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Voilà qui est intéressant, Andrei Alexandrescu vient tout juste de faire une présentation à la conf GoingNative (qui est live en ce moment) et tout une section de sa présentation était dédiée au fait que void GetPhotoList (const std::string& device_name, std::vector<std::string>& picture_list); est selon lui une bien meilleure interface que std::vector<std::string> GetPhotoList (const std::string& device_name);

    Les avantages selon lui :
    1) Plus composable
    2) plus efficace

    Précision importante, il part du principe que la forme avec la référence ajoute simplement à la fin du vecteur (faire des push_back en gros) plutôt que de réinitialiser et ajouter.

    Voici un des exemples qu'il donne pour montrer la supériorité de l'API par référence (il n'en parle qu'à l'oral, sans code, je transcris ce que j'en ai compris).
    L'api par référence permet de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::vector<std::string> v;
    while(some_condition)
    {
       v.clear();
       AppendPhotoList(somedir, v); // je l'appelle AppendPhotoList pour distinguer avec celle qui retourne par valeur
       DoSomething(v);
    }
    alors que l'api avec la valeur par retour oblige à faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(some_condition)
    {
       DoSomething(GetPhotoList(somedir));
    }
    Et dans ce cas naturellement la forme n°1 est bien plus efficace car dans la forme 2 la fonction GetPhotoList va recréer complètement un vecteur à chaque appel, donc à chaque tour de boucle le programme désallouera et reéallouera de la mémoire alors que le vecteur du code 1 finira par atteindre une capacité maximale et ne réallouera plus du tout.

  11. #31
    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 705
    Points
    2 705
    Par défaut
    Je pense que dans ton premier bout de code, la bonne expression est :


  12. #32
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Oui, merci, je corrige.

  13. #33
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Intéressant.
    En y réfléchissant, et en généralisant, je code bien plus souvent la première forme que la deuxième.
    Même si souvent j'hésite parce que c'est plus "lourd" (à taper et à relire).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //often recommended
    MyClass oi;
    while(some_condition)
    {
       //oi.init() or oi.clear(); whatever you need...
       GetByRef(someparam, oi);
       DoSomething(oi);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //less often
    while(some_condition)
    {
       MyClass oi=GetByVal(someparam);
       DoSomething(oi);
    }
    D'ailleurs parfois y'a pas le choix.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    MyClass1 o1;
    MyClass2 o2;
    while(some_condition)
    {
       GetByRef(someparam, o1, o2);
       DoSomething(o1, o2);
    }
    Il m'est arrivé alors d'utiliser des std::pair<> ou des tableaux de variant (des tuples, etc) comme valeur de retour.
    Oui... et puis non finalement.
    A la longue le retour par valeur des objets "complexes" est finalement pénible (je ne me suis toujours pas fait au retour de std::map<>.insert() par exemple).
    On a inventé les références, c'est pour s'en servir. Même si c'est plus ambigue, même s'il faut bien lire et comprendre la doc, même si c'est laid.

  14. #34
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Mais, j'y pense...
    J'aimerais pouvoir faire quelque chose comme ceci:
    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 MyClass1
    {
    int col;
    };
    class MyClass2
    {
    int row;
    };
     
    main()
    {
    std::pair<MyClass1, MyClass2> p=DoSometing();
    //Calc(p.first.col, p.second.row); // lourdingue...
    Calc(p..col, p..row);//accept this shorter syntax if there is no ambiguity
    }
    Je viens d'inventer l'opérateur ..
    Il permettrait de désigner un membre ou un sous-membre implicitement, pour autant qu'il n'y ai pas d'amguité.
    Vous en pensez quoi ?

  15. #35
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Perso je me prends surtout à rêver d'une syntaxe comme en go qui autorise les valeurs de retour multiples. Quelque chose comme ç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
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    DoSomething(void) -> MyClass1, MyClass2, bool
    {
       MyClass1 m1, m2;
       bool err = false;
     
       // code...
     
       return m1, m2, err;
    }
     
    main()
    {
       MyClass1 m1, MyClass2 m2, bool err = DoSomething();
       if(err )
         Calc(m1, m2);
     
       //
       // Note: En go on n'est pas obligé de définir tout sur la même ligne on peut 
       // aussi faire :
       // MyClass1 m1; MyClass2 m2;
       // ...
       // utilisation de m1 et m2 pour autre chose
       // ...
       // m1, m2, bool err = DoSomething();

  16. #36
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Les tuples sont tes amis (mais les tuples ont un gros défaut : l’absence de nommage de leurs composants, qui font que ça manque en général de sens. Les valeurs de retour ont le même problème, cela dit).

  17. #37
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Wah, Alexandrescu est d'accord avec moi! C'est la consécration, je vais le mettre sur mon cv!
    Bon par contre, on est d'accord sur la signature à utiliser, mais c'est pas pour les mêmes raisons

    edit: j'en profite pour faire une remarque sur l'argument de JolyLoic concernant le fait qu'une fonction qui retourne un conteneur permet de chainer des appels. Moi je n'aime pas chainer des appels (c'est une des raisons qui font que je n'utilise plus systématiquement la STL). Je préfère un peu plus de lignes de code, mais des lignes plus simples, plus atomiques, sémantiquement parlant. Mais c'est une pratique, une préférence, je ne sais pas si c'est mieux ou moins bien.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  18. #38
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par r0d Voir le message
    Wah, Alexandrescu est d'accord avec moi! C'est la consécration, je vais le mettre sur mon cv!
    Il est presque d'accord avec toi Car Alexandrescu ne ferait jamais ça :
    Citation Envoyé par r0d Voir le message
    - Dans ce cas de figure, je réinitialise systématique le conteneur (ici picture_list) au début de la fonction, généralement en utilisant un swap trick.
    Vu qu'avec un swap trick tu forces la désallocation de la mémoire du vecteur passé en référence, donc tu perds la moitié de l'intérêt à utiliser cette signature (pas d'allocation inutile si le vecteur a déjà une capacité suffisante)
    Citation Envoyé par r0d Voir le message
    Moi je n'aime pas chainer des appels (c'est une des raisons qui font que je n'utilise plus systématiquement la STL). Je préfère un peu plus de lignes de code, mais des lignes plus simples, plus atomiques, sémantiquement parlant.
    +1. Je n'aime pas chainer les appels non plus pour la simple raison que ça donne du code complètement indébuggable vu qu'on ne peut pas mettre de breakpoint pour vérifier étape par étape ce que renvoie chaque fonction.

  19. #39
    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 705
    Points
    2 705
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Les tuples sont tes amis (mais les tuples ont un gros défaut : l’absence de nommage de leurs composants, qui font que ça manque en général de sens. Les valeurs de retour ont le même problème, cela dit).
    Il faut les utiliser conjointement avec un enum dont les valeurs seront utilisées dans get().

  20. #40
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Voici un exemple dans un contexte de serialisation:
    -paramètre par référence pour sequence_in(), sequence_out(), ascending(), descending() (à cause des surcharges);
    -valeur retour pour permettre le chainage d'appel avec asc(), desc(), operator,() (bien pratique et très visuel dans ce cas-ci).

    input
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    //input
    template<typename Str>
    class sequencer_input
    {
    public:
    	sequencer_input(Str const & stream);
    	...
     
    	template<typename T>
    	sequencer_input & operator,(T & v)
    	{
    		sequence_in(*this, v);
    		return *this;
    	}
    };
     
    template<typename T, typename Str>
    bool run_sequencer_input(T & t, Str const & s)
    {
    	...
    	sequencer_input<Str> ts(s);
    	...
    	t.sequence(ts);
    	...
    	return success;
    }
     
    template<typename Str, typename T>
    void sequence_in(sequencer_input<Str> & ts, T & t)
    {
    	t.sequence(ts);
    }
     
    template<typename Str>
    void sequence_in(sequencer_input<Str> & ts, int & i)
    {
    	...
    }
     
    template<typename Str>
    void sequence_in(sequencer_input<Str> & ts, unsigned & u)
    {
    	...
    }
     
    template<typename Str>
    void sequence_in(sequencer_input<Str> & ts, std::string & s)
    {
    	...
    }
    output
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    //output
    template<typename Str>
    class sequencer_output
    {
    public:
    	sequencer_output(Str & stream);
    	...
     
    	template<typename T>
    	sequencer_output & operator,(T const & v)
    	{
    		sequence_out(*this, v);
    		return *this;
    	}
    };
     
    template<typename T, typename Str>
    bool run_sequencer_output(T const & t, Str & s)
    {
    	...
    	sequencer_output<Str> ts(s);
    	...
    	const_cast<T &>(t).sequence(ts);
    	...
    	return success;
    }
     
    template<typename Str, typename T>
    void sequence_out(sequencer_output<Str> & ts, T const & t)
    {
    	const_cast<T &>(t).sequence(ts);
    }
     
    template<typename Str>
    void sequence_out(sequencer_output<Str> & ts, int i)
    {
    	...
    }
     
    template<typename Str>
    void sequence_out(sequencer_output<Str> & ts, unsigned u)
    {
    	...
    }
     
    template<typename Str>
    void sequence_out(sequencer_output<Str> & ts, std::string const & s)
    {
    	...
    }
    order
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    //order
    class sequencer_order
    {
    	...
     
    	template<typename T>
    	sequencer_order & asc(T v)
    	{
    		ascending(*this, v);
    		return *this;
    	}
    	template<typename T>
    	sequencer_order & desc(T v)
    	{
    		descending(*this, v);
    		return *this;
    	}
    };
     
    inline void ascending(sequencer_order & sk, int i)
    {
    	...
    }
    inline void descending(sequencer_order & sk, int i)
    {
    	...
    }
     
    inline void ascending(sequencer_order & sk, unsigned u)
    {
    	...
    }
    inline void descending(sequencer_order & sk, unsigned u)
    {
    	...
    }
     
     
    inline void ascending(sequencer_order & sk, std::string const & s)
    {
    	...
    }
    inline void descending(sequencer_order & sk, std::string const & s)
    {
    	...
    }
     
    template<typename T>
    struct sequencer_order_pred
    {
    	mutable sequencer_order sk1, sk2;
    	void (T::*mf_)(sequencer_order &) const;	// the member function pointer
    	explicit sequencer_order_pred(void (T::*mf)(sequencer_order &) const): mf_(mf) {}
    	bool operator()(T const & v1, T const & v2) const
    	{
    		sk1.clear();
    		(v1.*mf_)(sk1);
    		sk2.clear();
    		(v2.*mf_)(sk2);
    		return ::memcmp(sk1.buffer(), sk2.buffer(), std::min(sk1.size(), sk2.size())) < 0;
    	}
    };
    Example d'utilisation, avec les méthodes descriptives MyRecord::sequence() et MyRecord::order_by().
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    struct MyRecord
    {
    	int m_age;
    	std::string m_nom, m_prenom;
     
    	template<typename F>
    	void sequence(F & f)
    	{
    		f, m_age, m_nom, m_prenom;
    	}
     
    	void order_by(sequencer_order & sk) const
    	{
    		sk.desc(m_age).asc(m_nom).asc(m_prenom);
    	}
    };
     
    main()
    {
    	//read
    	std::string si;
    	sequencer_input<std::string> stri(si);
    	std::vector<MyRecord> v;
     
    	...
     
    	MyRecord r;
    	while (cond)
    	{
    		if (run_sequencer_input(r, stri))
    		{
    			v.push_back(r);
    			...
    		}
    	}
     
    	...
     
    	//sort
    	std::sort(v.begin(), v.end(), sequencer_order_pred<MyRecord>(&MyRecord::order_by));
     
    	...
     
    	//write
    	std::string so;
    	sequencer_output<std::string> stro(so);
     
    	...
     
    	foreach (MyRecord r in v)
    	{
    		if (!run_sequencer_output(r, stro))
    		{
    			...
    		}
    	}
    }
    Bon, voilà, vite fait, comme ça, je ne sais pas ce que ça vaut
    Enfin, juste pour dire que les références sont privilégiées, c'est utile pour surcharger ou ajouter des indirections lorsque nécessaire.
    Exception faite lorsque la valeur retour est *this, j'adore chainer dans ce cas

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Apprendre avec de bonnes habitudes : Ada ou Pascal ?
    Par steiner81 dans le forum Débuter
    Réponses: 15
    Dernier message: 03/06/2007, 00h38
  2. Fonction polymorphe et conteneur stl.
    Par Captain Fizzou dans le forum SL & STL
    Réponses: 2
    Dernier message: 29/11/2004, 19h13
  3. question générale sur les conteneurs
    Par tut dans le forum C++
    Réponses: 6
    Dernier message: 01/09/2004, 10h11
  4. Conteneurs associatifs à clés dupliquées
    Par Christophe Brun dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 04/07/2004, 14h16

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