Partage
  • Partager sur Facebook
  • Partager sur Twitter

Probleme d'une classe template en attribut

Solutions et obligations

    2 juin 2008 à 20:23:01

    Bonjour à tous les zéros!
    Au cours de la réalisation d'un projet, je me suis retrouvé confronté à un problème mettant en cause les templates. Disons que j'ai trouvé une solution à ce problème, mais elle ne me satisfait pas vraiment.

    Voici un code d'exemple:
    La classe qui utilise un template:
    //ClasseTPL.hpp
    
    template <typename T>
    class ClasseTPL{
        private:
        T param;
        
        public:
        ClasseTPL(const T& cop = T()):param(cop){}
        
        const T& getParam() const{
            return param;
        }
        void setParam(const T& value){
            param=value;
        }
        
    };
    


    J'ai d'autre part:
    la classe conteneur qui possède un attribut du type ClasseTPL:
    //classeConteneur.hpp
    #include "classeTPL.hpp"
    
    template <typename T>
    class Conteneur{
        ClasseTPL<T> contenu;
        
        public:
            Conteneur(){}
            
            void setContenu(const ClasseTPL<T>& cont){
                contenu.setParam(cont.getParam());
            }
            
            const ClasseTPL<T>& getContenu() const{
                return contenu;
            }
        
    };
    


    Avec le main suivant:
    #include <iostream>
    #include "classeConteneur.hpp"
    
    using namespace std;
    
    int main(int argc, char** argv){
    
    /* _________________ Test de ClasseTPL ______________________*/
    
    ClasseTPL<int> test;
    test.setParam(3);
    
    cout<<"test1.getParam()="<<test.getParam()<<endl;
    
    Conteneur<int> cont;
    cont.setContenu(test);
    
    ClasseTPL<int> test2(cont.getContenu());
    
    cout<<"test2.getParam()="<<test2.getParam()<<endl;
    
    return 0;
    }
    


    J'obtiens la résultat logique suivant:
    test1.getParam()=3
    test2.getParam()=3


    Seulement, mon probleme, ou plutot l'interrogation, porte sur l'obligation d'utiliser un template pour le conteneur. Est-il possible d'utiliser un attribut comportant des templates sans que la classe conteneur doit elle-même déclarer le même type que l'attribut.

    En gros, ce que j'aimerai avoir c'est :

    Conteneur cont;
    cont.setContenu(test);

    sans avoir à spécifier le type <int> dans la déclaration de Conteneur.

    Des idées ou explications sur l'impossibilité de la chose?

    • Partager sur Facebook
    • Partager sur Twitter
      2 juin 2008 à 21:16:27

      Slt, tout d'abord, question ecriture... ça serait plus facile à lire si c'etait mieux indenté et surtout si tu sautais des espaces régulièrement...

      genre :

      cout<<"test2.getParam()="<<test2.getParam()<<endl;
      


      devient :

      cout << "test2.getParam()=" << test2.getParam() << endl;
      


      ou même :

      cout << "test2.getParam()="
           << test2.getParam() << endl;
      


      Tu peux mettre à volonté d'espaces entre 2, donc n'en économise pas!!! ;)
      Non seulement ça nous aide nous mais toi aussi pour te relire...

      Sinon, je n'ai pas bien compris ce que tu voulais faire... Eviter de rendre la classe conteneur générique???

      Sinon, si ça t'ennuie d'ecrire :

      Conteneur <int> cont;
      


      tu peux faire :

      typedef Conteneur <int> ContInt_t;
      ContInt_t cont;
      


      tu définis donc un type ContInt_t qui est un conteneur d'entiers que tu peux ensuite utiliser plus facilement. le _t t'ide à te souvenir que c'est un type définit!!!

      J'espère avoir bien compris ta question et si oui que ma réponse t'a aidé!!

      ++

      EDIT : Aussi, j'ai deux trois intérrogations...

      La première, pourquoi définir une classe générique qui n'a qu'une seule donnée membre...? Un int tout court n'aurait-il pas suffit???
      Et puis ta classe conteneur, elle ne contient ENCORE qu'une donnée membre générique...

      En gros, première classe, tu déclare une classe générique qui n'est autre qu'un objet du type instancié (ici int) et aprés tu redefinis une autre classe qui est elle meme un objet de te première classe qui est elle meme un objet de "base"...

      En gros tu crée deux classes pour arriver à avoir.... un Int... (en mois pratique puisqu'il lui faut des accesseurs et modifieurs... Ou alors est-ce seulement un code d'exemple trés trés simplifié pour montrer l'idée..?
      • Partager sur Facebook
      • Partager sur Twitter
        2 juin 2008 à 22:14:18

        @ Debian >> je penses que le but de cette question est d'illustrer la question.

        Si tu veux que ton Conteneur puisse contenir différent type de ClasseTPL tu n'as pas le choix. Ce que tu peux faire, parcontre, c'est des typedef.
        • Partager sur Facebook
        • Partager sur Twitter
          2 juin 2008 à 22:37:50

          Effectivement, la classe ClasseTPL n'a aucune autre utilité que d'illustrer mon interrogation. je pourrai expliquer dans quel cadre exactement la question est apparu, mais ce serait assez long...

          Le probleme est effectivement celui qu'a énoncé MatteX : utiliser différents types de ClasseTPL dans Conteneur, à la limite, qu'un Conteneur ne contiennent qu'un seul type de Classe TPL.

          En fait, ca me semble problématique dans la mesure où on pourrait avoir des classes qui se possèdent les unes les autres en cascade, et le template d'une classe "du bas" obligerait à faire monter le template sur toutes les classes propriétaires. je sais pas si c'est bien clair, j'éclaircirai au besoin.


          Cependant, une solution, dans certain cas, pourrait permettre d'avoir des conteneurs de différents types sans avoir à spécifier le type dans un template du conteneur, qui obligerait à avoir des types tous dérivés d'une même classe mère et de profiter du polymorphisme avec un typedef spécifiant le type de l'attribut du conteneur pour la classe mère. En gros, les types B, C et D descendent de A, et je fait un "typedef ClasseTPL<A> ClsTPLA;".

          Bon par contre, ca limite quand même pas mal. Si quelqu'un a une meilleure solution pour ne pas faire "remonter" une template d'un attribut vers le possesseur de l'attribut...
          • Partager sur Facebook
          • Partager sur Twitter
            2 juin 2008 à 22:55:35

            En fait, il existe deux possibilités de ne pas préciser le template : celui-ci est explicite (exemple avec une fonction somme<T>() qui prend 2 variables de type T en argument et qui renvoie leur somme : le type T n'a pas besoin d'être précisé si les deux arguments ont le même type) . Je ne pense pas que cela marche dans ton cas. Deuxième possibilité : on attribue au template une valeur par défaut. (exemple : template<typename T = int>) . Malheuresement, aucune de ces deux solutions ne peut résoudre ton problème.
            • Partager sur Facebook
            • Partager sur Twitter
              3 juin 2008 à 10:17:25

              Il n'y a que 3 cas de figure possibles, tous faciles à résoudre :

              1- Conteneur n'est fait que pour manipuler un type précis de données, dans ce cas il doit contenir directement le ClassTPL qui va bien (ClassTPL<int> par exemple).

              2- Conteneur est elle aussi une classe générique qui doit pouvoir être utilisée avec plusieurs types, dans ce cas il est logique qu'elle soit aussi template.

              3- Conteneur n'a pas à savoir quel type de données est manipulé par ClassTPL mais elle doit tout de même pouvoir accepter n'importe quelle instanciation de celle-ci, dans ce cas il faudra une classe de base non-template à ClassTPL, qui déclare toutes les fonctions nécessaires virtuelles ; le type utilisé dans la classe dérivée n'étant alors qu'un détail d'implémentation.

              Si tu as du mal à voir dans quel cas tu es, il va falloir nous en dire plus sur ce que tu souhaites faire.
              • Partager sur Facebook
              • Partager sur Twitter
                3 juin 2008 à 11:21:23

                En fait, à la base, j'ai le schéma suivant:
                Une classe Individu qui possède un template pour déterminer la taille d'un tableau d'entier dans ses attributs.
                Une classe population, qui possède elle aussi un template pour déterminer la taille de la population.
                En somme j'ai une déclaration qui ressemble à ca:
                template <int tailleIndiv>
                class Individu{
                int tab[tailleIndiv];
                }
                
                template <int taillePop, int tailleIndiv>
                class Population{
                vector<Individu<tailleIndiv>> pop;
                }
                


                C'est là que le probleme se pose, puisse que la population possédant un vecteur d'Individu, j'étais obligé de spécifier une valeur template indiquant la taille de l'individu.

                Ce qui me gênait était d'être obligé de fournir la taille de l'individu dans le template de population, dans la mesure où il n'y a pas vraiment de rapport conceptuel entre les 2. Je précise que lorsqu'une population est crée, elle contient des individus qui ont tous la même taille.

                Dans cette configuration, j'imagine que passer la taille d'un Individu à la construction de population est la seule solution technique possible aux vues des réponses qui m'ont été données dans ce topic. En effet, je me vois mal faire une classe par valeur de tailleIndiv possible, dans la mesure où ca peut changer d'une exécution du programme à une autre, et prendre des valeurs dans un intervalle assez large.

                J'ai finalement opté pour une solution différente, j'imagine que les templates n'étaient pas la bonne idée sur ce coup là! ^^

                Ceci dit, ca m'intrigue d'être obligé de spécifier la taille d'un individu dans la déclaration de Population.
                • Partager sur Facebook
                • Partager sur Twitter
                  3 juin 2008 à 13:33:03

                  struct IIndividu : boost::noncopyable
                  {
                      virtual ~IIndividu() { ... }
                      virtual ....
                  };
                  
                  template <size_t N> Individu : IIndividu {
                  private:
                      int tab[N];
                  };
                  
                  std::vector<IIndividu*> m_pop; // voire mieux: boost::ptr_vector<IIndividu>.
                  

                  Mais ... es-tu sûr que tu pourras déterminer la taille de chaque individu à la compilation, et non à l'exécution?
                  • Partager sur Facebook
                  • Partager sur Twitter
                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                    3 juin 2008 à 14:03:15

                    Si tu utilise un vector à la place d'un tableau "à la C", tu n'es pas obligé de connaître la taille à la compilation et par conséquent la passé comme argument au constructeur. Tu évites ainsi les templates.
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
                      3 juin 2008 à 14:16:34

                      Je pense qu'effectivement il y a peu d'intérêt à faire de la taille un paramètre template. Sauf bien sûr si tu as des contraintes particulières.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        3 juin 2008 à 19:13:13

                        Disons que le probleme de la taille du tableau a été l'occasion de rencontrer le problème de la "remontée" du template sur les classes contenante. Cela dit, j'imagine que ce genre de probleme ne doit pas se recontrer si la conception est correcte.

                        De toutes facons, j'ai choisi une autre orientation dans le programme que je réalisais, donc la question ne se pose plus en pratique pour moi, juste que ca m'intriguait que rien n'ai été prévu pour qu'on puisse utiliser un type utilisant un template sans avoir à spécifier l'argument dans la déclaration.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          3 juin 2008 à 20:38:37

                          Citation : Pas de titre

                          juste que ca m'intriguait que rien n'ai été prévu pour qu'on puisse utiliser un type utilisant un template sans avoir à spécifier l'argument dans la déclaration


                          Le C++ c'est pas magique, et en outre le typage doit être résolu à la compilation. Si le conteneur ne sait pas quelle instanciation du template il doit manipuler, le compilo ne va pas pouvoir faire grand chose. Donc à toi de le spécifier, soit en le fixant soit en rendant le conteneur lui-même template.

                          N'oublie pas qu'un template n'est pas une classe mais seulement un modèle de classe. D'autant plus qu'avec la spécialisation, deux instanciations du même templates peuvent différer du tout au tout. Faut pas spécialement croire que différentes instanciations de template aient quoique ce soit en commun, Truc<int> et Truc<string> peuvent être tout aussi différentes que Maison et Personnage.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            3 juin 2008 à 23:11:32

                            Citation : Laurent Gomila

                            Faut pas spécialement croire que différentes instanciations de template aient quoique ce soit en commun, Truc<int> et Truc<string> peuvent être tout aussi différentes que Maison et Personnage.


                            Ok, c'est surtout ca qui est trompeur. On pourrait penser qu'il y a un moyen de rassembler des classes Truc<int> et Truc<string> sous un même type englobant. Merci pour les précisions.
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Probleme d'une classe template en attribut

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                            • Editeur
                            • Markdown