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 :

Vector de templates


Sujet :

SL & STL C++

  1. #1
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 73
    Points : 68
    Points
    68
    Par défaut Vector de templates
    Bonjour,

    J'ai un problème concernant les templates. Je voudrais pouvoir stocker des pointeurs vers des objets templates hétérogènes dans un vector de la stl, mais je n'ai pas l'impression que cela soit possible...

    Pour être un peu plus compréhensible, j'ai une classe template MaClasse :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template <typename T>
    class MaClasse : public Base {
      protected: 
        T & value_;
     
      public:
        MaClasse(const T & inValue) : value_(inValue) {}
      ...
    }

    et j'aimerais pouvoir créer un vector de pointeurs de MaClasse, autrement dit avoir quelque chose comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    std::vector<MaClasse*> vec;
    int i = 10;
    string s = "toto";
     
    vec.push_back(new MaClasse<int>(i));
    vec.push_back(new MaClasse<string>(s));
    La seule solution que j'ai trouvé, c'est d'utiliser un vector de Base *, mais ca ne m'arrange pas trop puisque d'autres classes dérivent de Base, et je ne veux pas d'elles dans mon vector.

    Merci d'avance pour vos idées !

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Points : 440
    Points
    440
    Par défaut
    ton besoin n est pas tres clair ...

    en tout cas une syntaxe telle quelle n est pas possible .


    tu peux toujours inserer un nouvelle classe de base

    class InserableBase : public Base {};

    template<typename T> class MaClass : public InserableClass ....


    vector<InserableClass *> ...


    sinon, tu peux voir ce qui ce fait du cote boost::any , mais n empechera pas alors de bloquer des insertion

  3. #3
    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
    Ta base commune c'est Base, pas MaClasse.
    std::vector<Base*> vec;
    Boost ftw

  4. #4
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut
    Je cromprend pas comment tu arrive a compiler ton code.
    Tu declare une classe template donc pour l'utiliser tu doit la déclarer comme ceci :Donc pour définir un vecteur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<MaClasse<double>> vec;
    ________________________________________________
    http://bliquid.fr : Blog sur Android et l'Acer Liquid

  5. #5
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 73
    Points : 68
    Points
    68
    Par défaut
    Non non, ce code ne compile pas, c'était juste pour expliquer ce que je voudrais avoir.

    En fait, mon but est d'avoir un vector d'objets hétérogènes, pouvant contenir à la fois des objets de types de base (int, float, string) et des instances de classes. J'avais pensé à utiliser un vector<void *>, mais je ne pouvais alors pas récupérer le type de la classe pour le déréférencement du pointeur, mes objets pointés étaient inutilisables. Je me suis donc dit qu'utiliser une classe template pour stocker des références à ces objets pouvaient être une bonne idée, de cette façon le type était connu et je pouvais appeler des méthodes sans problèmes sur les objets contenus dans mon vector.

    A priori je vais donc être obligé de passer par un vector<Base *>, je l'encapsulerais dans une classe pour empêcher les insertions non voulues.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 370
    Points : 41 523
    Points
    41 523
    Par défaut
    Tu peux aussi faire le même principe que les VARIANT : Un gros union prenant en charge certains types (pas d'objet complexe par valeur), et un champ avec une énumération indiquant le type en cours...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Points : 440
    Points
    440
    Par défaut
    si tu veux faire un container qui peut contenir n importe quoi , tu peux utiliser boost::any !!!

    std::vector<boost::any> v;

    v.push_back(any(3));

    v.push_back(any(3.14));

    v.push_back(any(new MaClass));

    ...

    ton vecteur contiendra n importe quoi ... apres (de memoire du peut faire quelque chose comme)

    any a = 3;

    any_cast<int> (a) <-- te retourne 3 (ou lance une exception si a ne contient pas de donnee de type entier .

    Comment ca marche ? (ca donne quelquechose comme ...)


    class any {

    private:

    class content {

    public:

    content(const type_info & ti) : my_type(ti){}

    virtual ~content(){}

    const type_info &
    };

    template<typename T> class content_impl : public content {

    public:

    template<typename T> content_impl(T t) : content(typeid(T)) , value(t){}

    T value;
    };

    public:

    template<typename T> any(T t) : my_data(new content_impl<T>(t)){}

    private:

    content * my_data;

    };


    en gros any est un pointeur sur des donnees quelconques, et connait le type_info des donnees sur lesquels il pointe.

    note : j espere un jour envoye une lib que je suis en train d ecrire sur le sujet

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 370
    Points : 41 523
    Points
    41 523
    Par défaut
    L'inconvénient de any, c'est qu'il utilise l'allocation dynamique pour tous les types, y compris un simple entier...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    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
    Quand l'ensemble des types est parfaitement connu : c'est boost::variant qu'il faut utiliser. On a la garantie qu'il ne contiendra que les types spécifiés.

    http://www.boost.org/doc/html/variant.html

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Points : 440
    Points
    440
    Par défaut
    Citation Envoyé par Médinoc
    L'inconvénient de any, c'est qu'il utilise l'allocation dynamique pour tous les types, y compris un simple entier...
    absolument , c 'est le prix de la modularite (avec un cast plus sure que static_cast)


    effectivement, apres la precedente piqure de rappel , boost::variant correspond probablement plus au besoiun

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Points : 440
    Points
    440
    Par défaut
    note : test a verifier !!!


    void * operator new (size_t t){

    printf("allocation de %d octets\n",t);

    return malloc(t);
    };

    sous linux(gcc) , quand on fait quelquechose comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for (int i = 0 ;i < 100 ; ++i)
     
      new MaClass;
    on s appercoit que les allocations sont pas aussi nombreuses que ce que l on attend (100) , mais de taille > sizeof(MaClass).

    Ceci signifierai (a verifier) que le compilateur est capable d '"amortir" les allocations . Donc meme si any force une allocation , le cout n est pas necessairement prohibitif a l usage

  12. #12
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 73
    Points : 68
    Points
    68
    Par défaut
    Effectivement, après m'être renseigné sur variant, il s'avère que cela correspond exactement à ce dont j'ai besoin. Il me suffit de créer une interface dont hériterons les classes que j'accepte dans mon vector, et je peux alors créer le vecteur suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<boost::variant< MonInterface*, int*, bool*, float*, std::string*> >
    et utiliser un visiteur générique pour effectuer mes opérations sur les objets du vecteur. Et du coup je n'ai plus besoin de la classe template MaClasse.

    Merci bien pour cette solution !

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 370
    Points : 41 523
    Points
    41 523
    Par défaut
    Es-tu sûr que tu as besoin de pointeurs pour ton variant ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 73
    Points : 68
    Points
    68
    Par défaut
    J'ai besoin de pointeurs pour utiliser le polymorphisme. Du coup j'utilise aussi des pointeurs d'entier, de flottant etc pour pouvoir écrire un visiteur générique, par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class increment : public boost::static_visitor<> {
      public:
     
        template <typename T>
        void operator()(T & operand) const
        {
            (*operand)++;
        }
    };
    (Je n'ai pas testé, mais je pense que ça doit marcher... )

  15. #15
    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
    T'as pas besoin de pointeurs pour les int/float/std::string.

    Spécialise plutôt ton visiteur pour les pointeurs vers ton interface, et laisse le reste de manière générique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class visiteur : public boost::static_visitor<> {
    public:
        void operator()(MonInterface* pI) const
        {
            // traitement
        }
     
        template <typename T>
        void operator()(T & operand) const
        {
            // les autres types
        }
    };
    PS : tu devrais faire un typedef pour ton variant...

  16. #16
    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
    Le fait d'utiliser la pile pour stocker l'objet pose d'autres problèmes.
    Pour l'opérateur=, si les types ne concordent pas, il faut détruire l'ancien objet puis copier le nouveau.
    Si la copie lève une exception, il faudrait pouvoir remettre l'ancienne valeur. Or, cette ancienne valeur a priori on l'a plus.
    Il faut donc avoir un stockage double de l'objet, avec un booléen indiquant dans quel stockage est l'objet. (l'un des deux stockages est dans boost.variant à base d'allocation dynamique)
    Boost ftw

Discussions similaires

  1. pointeur sur un vector de template
    Par Shibron dans le forum Langage
    Réponses: 5
    Dernier message: 29/04/2011, 15h33
  2. Template - vector - iterator
    Par jmeuf dans le forum Langage
    Réponses: 6
    Dernier message: 30/03/2007, 13h42
  3. template et std::vector
    Par themadmax dans le forum Langage
    Réponses: 9
    Dernier message: 26/07/2006, 10h41
  4. Réponses: 13
    Dernier message: 03/10/2005, 18h06

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