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érateurs " génériques "


Sujet :

SL & STL C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut Itérateurs " génériques "
    Bonjour,

    J'ai actuellement une interface A dont une méthode prend un vecteur de X et une autre interface B retournant un vecteur de X.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A
    {
                   virtual void foo(const std::vector<X> &) = 0;
    }
     
    class B
    {
                  virtual const std::vector<X> & foo(void) = 0;
    }
    Vous l'aurez compris, le but est de faire :
    Mais j'aimerais faire quelque chose de plus générique pour permettre aux classes implémentant l'interface B d'utiliser d'autres conteneurs qu'un std::vector<X>.
    J'aimerais donc avoir quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A
    {
                   virtual void foo(constIterator<X>, constIterator<X>) = 0;
    }
     
    class B
    {
                  virtual std::pair<constIterator<X>, constIterator<X> > foo(void) = 0;
                  // ou const IConteneur & foo(void) = 0; où IConteneur n'a que deux méthodes : begin() et end(). 
    }
    En effet, dans A, je dois juste parcourir le conteneur, et je me moque un peu de son type.
    Pour faire cela, la STL utilise des templates (cf std::vector::vector() ).

    Or, je ne suis pas sûr que les templates "virtuelles" existent .
    Je me demandais donc si la STL n'avais pas une solution à ce niveau-là ou s'il n'existait pas un idiome ou un DP pour ceci.

  2. #2
    Membre Expert

    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 : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonjour,

    Il existe peut-être une solution, mais pour ça il faudrait que tu nous montres pourquoi ces fonctions doivent être virtuelles. Si tu peux utiliser boost, je t'invite à regarder boost.range qui contient ce que tu as besoin (any_range).

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    il faudrait que tu nous montres pourquoi ces fonctions doivent être virtuelles.
    Parce que A et B sont des interfaces .

    Je donne leurs interfaces et derrière, je n'ai pas d'à priori sur la manière dont ils seront implémentés.
    Je peux même avoir plusieurs implémentation et choisir celle que je veux.

    Derrière, je vais avoir un DP façade qui va utiliser les deux interfaces, mais je pourrais donner à cette façade l'implémentation que je souhaite.

    Citation Envoyé par Flob90 Voir le message
    Si tu peux utiliser boost, je t'invite à regarder boost.range qui contient ce que tu as besoin (any_range).
    Je ne peux malheureusement qu'utiliser la bibliothèque standard.

  4. #4
    Membre Expert

    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 : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Ceci dit boost.range est header only, donc tu peux toujours isoler et inclure dans ton projet directement les fichiers de boost.range.

    Sans ça, il n'y a rien de standard pour ça actuellement (boost.range, du moins l'idée qui est derrière, sera surement standard en C++17, mais je ne crois pas qu'un type erasure pour le concept de range soit prévu actuellement).

    Si tu veux le faire à la main, il s'agit de mettre en place un type erasure qui convient à tes besoins. Tu auras des infos sur des implémentations de ce genre en cherchant any_iterator et any_range sur google.

    AMA, c'est une erreur que ces fonctions soient virtuelles. Je te suggérerais bien des alternatives mais il faut plus de détail sur la situation réelle.

  5. #5
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    En gros, j'ai 5 interfaces :
    • moduleFileSystem : gère le "chemin" des modules dans le système de fichier ;
    • moduleInfo : donne les informations sur un module ;
    • moduleDependancies : on lui donne une liste de modules et il établit l'ordre de chargement des modules selon leurs dépendances ;
    • moduleLoader : charge les modules ;
    • moduleManager : façade.


    Donc, je vais avoir des méthodes qui vont retourner des ensembles :
    • moduleFileSystem::modulesEnabled() : ensemble des modules "activé" ie contenu dans un dossier particulier ;
    • moduleInfo::loadInfo() : donne la liste des informations des modules dont les chemins sont passés en paramètre ;
    • moduleDependancies::computeOrder() : donne l'ordre de chargement des modules dont les informations sont passés en paramètres ;


    Et je vais avoir des méthodes qui vont prendre en entrée des ensembles :
    • moduleInfo::loadInfo()
    • moduleDependancies::computeOrder()
    • moduleLoader::loadModules()


    Chaque classe étant totalement indépendante, ce qui est logique :
    • la façon de stocker les modules peut varier (dossiers, fichier de configuration, BDD, etc.) ;
    • la façon de récupérer les informations et de les stocker pour un accès futur n'a rien à voir avec la manière dont les modules sont stockés ;
    • le calcul de l'ordre de chargement selon les dépendance est un algorithme qui n'a pas à savoir comment récupérer les informations ou de savoir comment les modules sont stockés.
      On peut aussi trouver d'autres algorithmes ou d'autres façon de gérer certains problèmes de dépendances.
    • Le chargement des modules est bête et méchant.


    Ainsi chacune de mes classes a une responsabilité unique, simple et bien définie.
    Je peux ainsi changer au sein de ma façade certains composants.

    C'est donc pour cela que j'ai besoin d'interfaces.

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    J'ai trouvé un exemple de type erasure ici.

    Si j'ai bien compris on fait :
    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
    class Iterator
    {
          class IteratorConcept
          {
                virtual void foo(void)  = 0;
          };
     
          template<typename T>
          class IteratorConcrete : public IteratorConcept
          {
               IteratorConcrete(const T &) : T(it){}
               virtual void foo(void){ it.foo(); }
               T it;
          };
     
          IteratorConcept * m_ptr;
          public :
               void foo(void){ m_ptr->foo(); }
     
               template<typename T>
               Iterator( const T & ptr) : m_ptr(new IteratorConcrete<T>(ptr){}
    }
    Par contre, je ne comprend pas pourquoi on encapsule "IteratorConcept" dans la classe "Iterator".
    C'est pour permettre la copie de "Iterator" ?

  7. #7
    Membre Expert

    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 : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Et tu vas stocker dans des conteneurs des pointeurs de moduleFileSystem (ou une autre de tes interfaces) ? Si ce n'est pas le cas, je ne vois aucune raison de faire une classe de base. Une définition de chacun de ces concepts bien documenté suffit.

    Tu n'es pas obliger de mettre la classe dedans, personnellement j'évite des classes internes à d'autre classe pour un type erasure.
    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
     
    struct base_iterator
    { 
      /*ici les fonctions virtuelles pures qui conviennent pour un itérateur*/ 
      virtual void foo() =0;
    };
     
    template<class Iterator>
    struct concrete_iterator : base_iterator
    {
      /*ici implémentation des fonctions virtuelles pures en utilisant it*/
      void foo()
      { it.foo(); }
     
    private:
      Iterator it;
    };
     
    struct any_iterator
    {
      template<class Iterator>
      any_iterator(Iterator&& it)
        : ptr(std::make_unique<concrete_iterator<Iterator>>(std::forward(it)))
      { }
      /*implémentation des fonctions non virtuelles qui conviennent à un itérateur*/
      void foo()
      { ptr->foo(); }
     
    private:
      std::unique_ptr<base_iterator> ptr;
    };
    Tu peux rajouter des paramètres dans la classe de base tant que tu les rajoutes partout.

+ Répondre à la discussion
Cette discussion est résolue.

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