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 :

Algorithm, Foncteur et organisation du code


Sujet :

SL & STL C++

  1. #1
    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 Algorithm, Foncteur et organisation du code
    Bonjour,

    J’ai récemment découvert les algorithmes de la STL et les foncteurs en particulier. Grâce à la F.A.Q et à ce forum j’y commence à y voir un peu plus clair. En revanche, je suis toujours dans le noir complet sur la manière dont on les utilise dans du vrai code de production (ou même au-delà d’un exemple de quelques lignes) et sur la manière dont on organise son code quand il y a des foncteurs.

    Actuellement je suis sur un projet contenant des centaines et des centaines de .cpp et .h, Si j’introduis quelques foncteurs, il est primordial qu’ils restent très localisés et soient faciles à trouver, à comprendre et à utiliser par d’autres programmeurs.

    Pour mieux comprendre j’ai cherché à modifier le projet donné en exemple ici:
    http://r0d.developpez.com/articles/algos-stl/#LI-E-3

    Il est très simple mais soulève déjà pas mal de question. On a une classe album contenant un titre, un chanteur, une année, un genre etc. et une classe AlbumManager contenant un vecteur d’Album. On cherche à trouver grâce à un prédicat si le titre d’un album quelqueconque passé en paramètre est présent dans le vecteur.


    Première solution : le prédicat est une méthode de la classe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    // Dans le fichier album.h
    // HaveSameTitle est un prédicat qui retourne true si le titre passé en paramètre est le même que celui de l’album
    bool HaveSameTitle(std::string title) const { return title_ == title;)
    Avantage :
    . Court
    . Simple à comprendre, simple à trouver (dans la classe).
    . Le prédicat peut accéder aux données privées de la classe.

    Inconvénient :

    L’utilisation : Il semble que le seul moyen d’utiliser ce genre de prédicat soit cette horreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    std::string title = "Led Zeppelin";
    AlbumList::iterator searched =  
       std::find_if(main_list_.begin(), main_list_.end(),
          std::bind2nd (std::mem_fun_ref<bool, Album, std::string>(&Album::HaveSameTitle), title) );
    Et là, non. C’est juste trop lourd et trop confus. La plupart de mes collègues utilisent la STL pour les conteneurs et quelques algos de base, je ne peux donc pas introduire ce genre de subtilité ésotérique au beau milieu de code.

    Deuxième solution : Le prédicat est une structure dont on redéfinit l’opérateur()

    On a alors dans le .h de la classe Album
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct AlbumHaveSameTitle : public std::unary_function<Album, bool>
    {
       AlbumHaveSameTitle(const std::string& title);
       bool operator() (const Album& album) const;
       std::string title_;
    };
    Et dans le .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    AlbumHaveSameTitle::AlbumHaveSameTitle(const std::string& title)
    : title_(title)
    {}
     
    bool AlbumHaveSameTitle::operator() ( const Album& album ) const 
    { 
       return album.GetTitle() == title_; 
    }
    Avantage :

    On a enin une utilisation simple et logique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::string title = "Led Zeppelin";
    AlbumList::iterator searched = 
       std::find_if ( main_list_.begin(), main_list_.end(), AlbumHaveSameTitle(title) );
    Inconvénient :

    . On ne peut pas accéder aux variables privées de la classe Album. Il faut donc mettre des accesseurs partout.
    . Ca reste tout de même un peu confus, quand on le rencontre pour la première fois (une sructure dont on redéfinit l’operateur() !? Pas banal...)
    . Assez lourd. Au final il faut 13 lignes pour écrire un béte == . Sachant qu’il y peut y avoir pas mal de foncteur (après tout on peut chercher les albums par titre, par chanteur, par genre, par année, mais on peut ausssi imaginer plein d’autre prédicat). Le fichier album.cpp et album.h va vite être saturé de déclaration de structure.
    . Les structures sont globales. Je n’ai pas trop envie de polluer le namespace (qui contient déjà de nombreuses classe) par plein de nouvelles structures volantes.

    Voilà où j’en suis actuellement. J’avoue que cette première évaluation des algos de la STL m’a un peu découragé. La méthode basique, sans algo et foncteur, semble bien plus simple au final.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // dans le fichier album.h
    Bool Album::EqualTitel(const std ::string title) const { return _title == title);
     
    // quelques parts dans le code
    std::string title = "Led Zeppelin";
    Std::vector<Album>::iterator it;
    For(it = catalogue.begin(), catalogue.end(), ++it)
    {
       if(it->EqualTitle(title) == true)
       {
          // do something
       }
    }

    D’où ma question. Si vous utilisez des foncteurs dans du code de production, comment organisez-vous votre code, quelle présentation adoptez-vous ? Des bind2nd, bind1st et autres mem_ref_fun illisibles ? Pleins de struct globales qui se baladent partout ? Une autre solution ?

    Merci d’avance !

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    salut
    . On ne peut pas accéder aux variables privées de la classe Album. Il faut donc mettre des accesseurs partout.
    Pourquoi aurais tu besoin de tout cela? soit tu fait un traitement à partir de l'objet, soit tu lui applique un traitement.

    . Ca reste tout de même un peu confus, quand on le rencontre pour la première fois (une sructure dont on redéfinit l’operateur() !? Pas banal...)
    Ben si, des qu'il y as des foncteurs

    . Assez lourd. Au final il faut 13 lignes pour écrire un béte == . Sachant qu’il y peut y avoir pas mal de foncteur (après tout on peut chercher les albums par titre, par chanteur, par genre, par année, mais on peut ausssi imaginer plein d’autre prédicat). Le fichier album.cpp et album.h va vite être saturé de déclaration de structure.
    tu n'est pas obligé de séparé la definition de la class. Si tu met tous ensemble tu donne la possibilité de l'inline au compilo. De plus, souvent les foncteur son template.

    . Les structures sont globales. Je n’ai pas trop envie de polluer le namespace (qui contient déjà de nombreuses classe) par plein de nouvelles structures volantes.
    Tu pourrais faire un namespace specialisé

    Voilà où j’en suis actuellement. J’avoue que cette première évaluation des algos de la STL m’a un peu découragé. La méthode basique, sans algo et foncteur, semble bien plus simple au final.
    mais surement moins performante et surtout risque d'une erreur de parcoure.
    Les algo peuvent optimiser (car ils savent le faire) le parcoure des iterateur.

    D’où ma question. Si vous utilisez des foncteurs dans du code de production, comment organisez-vous votre code, quelle présentation adoptez-vous ? Des bind2nd, bind1st et autres mem_ref_fun illisibles ? Pleins de struct globales qui se baladent partout ? Une autre solution ?
    La je ne pense pas qu'il y est une bonne réponse. Perso, j'ecrit mes foncteurs spécialisé au endroit où je les utilise.
    Que critique tu au bind1st, bind2nd...? leur but et de pouvoir utiliser des foncteurs le plus générique possible.

  3. #3
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968

  4. #4
    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
    Points : 4 625
    Points
    4 625
    Par défaut
    remplace
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::bind2nd (std::mem_fun_ref<bool, Album, std::string>(&Album::HaveSameTitle), title)
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::bind(&Album::HaveSameTitle, _1, title)
    Boost ftw

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Points : 1 176
    Points
    1 176
    Par défaut
    C'est pas une solution mieux par rapport à l'autre. Tu peux utiliser les bind pour créer des functors à la volée et tu peux utiliser des functors que tu as fait toi même pour des cas plus complexe ( ou tu as besoin de garder des états par exempe ).

    Pour l'endroit où je défini le functor, ça dépend. Si j'en ai besoin que dans le .cpp d'un objet, je le met à cet endroit.
    Si j'en ai besoin de manière globale et qu'il est lié à une classe, je le déclare dans la classe.

    Si j'en ai besoin de manière encore plus globale, ça peut être un nouveau .h/.cpp dédié au functor. Dans un nouveau namespace si besoin.


    Sinon, en C++, un functor c'est banal. C'est pas une partie ésotérique du langage. Tous les algorithmes de la STL sont prévus pour être utilisé de cette façon.

  6. #6
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Citation Envoyé par nikko34 Voir le message
    Sinon, en C++, un functor c'est banal. C'est pas une partie ésotérique du langage. Tous les algorithmes de la STL sont prévus pour être utilisé de cette façon.
    Pas forcément, par des fonctions aussi.
    C'est quand même plus parlant qu'un foncteur explicitement écrit.

    D'ailleurs, on en parlait récemment de ça : http://www.developpez.net/forums/d60...lgo-foncteurs/

  7. #7
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Citation Envoyé par Mongaulois Voir le message
    Tu pourrais faire un namespace specialisé
    Ou un namespace anonyme l'avantage étant que tout reste local et caché dans le .cpp

    MAT.

Discussions similaires

  1. Persistance et organisation du code
    Par K-Kaï dans le forum Hibernate
    Réponses: 16
    Dernier message: 06/06/2007, 17h01
  2. Organisation du code source
    Par _kal_ dans le forum C
    Réponses: 18
    Dernier message: 04/08/2006, 14h15
  3. organisation du code.
    Par poporiding dans le forum C++
    Réponses: 36
    Dernier message: 13/07/2006, 10h15
  4. organisation du code.
    Par poporiding dans le forum C++
    Réponses: 3
    Dernier message: 28/06/2006, 17h10
  5. Réponses: 4
    Dernier message: 19/09/2005, 17h56

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