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 :

Problème liste de template


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut Problème liste de template
    Bonjour à tous,

    Après un retour de vacances je me remets au boulot et me retrouve confronté aux problèmes d'avant de partir
    Pour vous exposer mon problème je vais synthétiser les étapes de mon problème.
    Je dois faire un programme ou l'utilisateur crée des variables.
    Au départ mon responsable m'avait dit d'utiliser une structure pour stocker la variable 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
    16
    17
    18
    19
    enum	TYPE_CODAGE
      {
        LIBRE	=	0,
        ENT,
        ENT_S,
        REEL,
        ENUM,
        BOOLEEN,
        ASCII,
        TABLEAU,
        COMPLEXE,
        FICHIER_TECHNIQUE,
      };
     
    struct sData
    {
    TYPE_CODAGE type;
    long long valeur;
    };
    Et quand je devais crée une variable je faisais un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    QVector<sData> datas;
    sData data1;
    sData data2;
    //Si l'utilisateur a crée un int
    data1.TYPE_CODAGE = ENT_S;
    *(data1.valeur) = reinterpret_cast<long long*>(&MonInt);
    //Si l'utilisateur crée un float
    data2.TYPE_CODAGE = REEL;
    *(data2.valeur) = reinterpret_cast<long long*>(&MonFloat);
    datas.push_back(data1);
    datas.push_back(data2);
    Bon voila c'était pas opti je pense surtout que je devais caster à tout va. Pour stocker ou lire les variables dans le type souhaité.
    Puis je suis passé à un truc comme ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    union			Type
    {
      qint64		tInt;
      quint64		tUInt;
      double		tDouble;
      char			tChar[8];
    };
     
    struct sData
    {
    TYPE_CODAGE type;
    Type valeur;
    };
    Et quand je devais crée une variable je faisais un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    QVector<sData> datas;
    sData data1;
    sData data2;
    //Si l'utilisateur a crée un int
    data1.TYPE_CODAGE = ENT_S;
    data1.valeur.tInt = MonInt;
    //Si l'utilisateur crée un float
    data2.TYPE_CODAGE = REEL;
    data2.valeur.tDouble = monFloat;
    datas.push_back(data1);
    datas.push_back(data2);
    C'était un peu mieux mais bon le problème c'est que quelque soit le type, la valeur est stockée sur 8octets. Si on veut un int et qu'on le stocke dans 8octets cela pose problème quand on veut ensuite l'écrire une fonction comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T>
    void read(T& val, const unsigned char* data, int msb, int lsb, bool big_endian=true)
    {
        const size_t size = sizeof(T);
        typedef typename unsigned_<size>::type type;
        type *ptr = reinterpret_cast<type*>(&val);
        for(size_t i=0; i<size; ++i)
            ptr[big_endian ? size-i-1: i] = data[i];
        val <<= (sizeof(val) * CHAR_BIT - msb - 1);
        val >>= lsb;
    }
    On écrit 8octets même si la variable en contient moins.. Pas malin..
    Donc j'ai eu une longue conversation avec koala01 qui m'a convaincu d'utiliser des templates pour ma structure. Cela donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename Type>
    struct sData
    {
        /* ca, c'est juste pour pouvoir récupérer le type en cas de besoin ;) */
        using value_type = Type ;
        enum{accessSize = sizeof(Type)}; // la taille réellement utilisée en mémoire par Type (en bytes ;) )
        value_type original; // la valeur d'origine (dans son type d'origine)
    };
    C'est niquel et cela colle avec la fonction readn !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    sData data1;
    sData data2;
    //Si l'utilisateur a crée un int
    sData<int> data1;
    data1.original = MonInt;
    //Si l'utilisateur crée un float
    sData<float> data2;
    data2.original = MonFloat;
    /*Maintenant je veux stocker les deux structures dans une liste ou tableau (n'est ce pas un des principes de l'informatique? Regrouper ce qui se ressemble, qui a un lien.Donc j'essaye de faire cela :*/
    QVector<Type> datas; // Je sais que c'est n'importe pas mais je vois pas comment faire..
    //pour pouvoir faire:
    datas.push_back(data1);
    datas.push_back(data2);
    Voila où j'en suis, je n'arrive pas à regrouper mes structures templates. Car si c'est pour avoir une liste d'int, une de float, une d' unsigned int et les remplir en fonction du type template, non merci quoi !
    J'ai l'impression d'être un peu f**ked et que finalement la meilleur solution était la première (ou finalement aucune des trois..)
    Merci d'avance si quelqu'un a une solution.

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Salut,

    Je ne sais pas si tu peux utiliser Boost, mais je pense que Boost::Variant peut être utile pour ce que tu cherches à faire. (http://www.boost.org/doc/libs/1_54_0...l/variant.html)

    Voici un cour exemple:
    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
     
    #include <iostream>
    #include <vector>
    #include <boost/variant.hpp>
     
    int main()
    {
       typedef boost::variant<int, long, double, float> Types;
       std::vector<Types> dataVec;
     
       dataVec.push_back(1);
       dataVec.push_back(2l);
       dataVec.push_back(3.0);
       dataVec.push_back(4.0f);
     
       for (int i=0; i<dataVec.size(); ++i)
       {
           std::cout << dataVec[i].type().name() << std::endl;
       }
     
      return 0;
    }

  3. #3
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    L'effacement de type serait une solution? je n'ai pas trop bien compris ton problème mais peux être ceci pourrais t'aider :
    http://h-deb.clg.qc.ca/Sujets/Divers...-de-types.html

    Boost::Any autrement.
    Homer J. Simpson


  4. #4
    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 j'ai l'impression que ta solution numéro 2 est la meilleure, surtout si les conditions suivantes sont remplies :

    - La liste des types de variable (ENT, REEL, BOOLEAN etc..) est fixée et ne changera pas (ou très peu)
    - La contrainte principal est de pouvoir facilement créer des listes ou autres conteneurs regroupant des "variables" de n'importe quel type.

    Et en fait je n'ai pas bien compris ce qui t'as poussé à abandonner cette solution. Le problème que tu évoques avec la fonction template read() me semble assez simple à contourner, par exemple en créant une surcharge plus spécialisée de read qui accepte un sData en paramètre et qui dispatch en fonction du type.
    Par exemple : (un peu simplifié car je ne n'ai pas bien compris le coup du msb, lsb c'est un peu confus)
    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
     
    template <class T>
    void read(T& val, const unsigned char* data, bool big_endian = true)
    {
    	const size_t size = sizeof(T);
    	char*ptr = reinterpret_cast<char*>(&val);
    	for (size_t i = 0; i < size; ++i)
    		ptr[big_endian ? size - i - 1 : i] = data[i];
    }
     
    void read(unsigned char* val, int size, const unsigned char* data, bool big_endian = true)
    {
    	for (size_t i = 0; i < size; ++i)
    		val[big_endian ? size - i - 1 : i] = data[i];
    }
     
    void read(sData& d, const unsigned char* data, bool big_endian = true)
    {
    	switch (d.type)
    	{
    	case ENT:
    		read(d.valeur.tInt, data, big_endian);
    		break;
    	case REEL:
    		read(d.valeur.tDouble, data, big_endian);
    		break;
    	case ASCII:
    		read(d.valeur.tChar, sizeof(d.valeur.tChar), data, big_endian);
    		break;
            // etc...
    	}
    }
    Alors c'est sur, ça fait faire quelques switch case à ralonge, mais si la liste est assez limitée, après tout pourquoi pas ? Et d'ailleurs en faisant l'exercice je suis tombé sur un autre problème qui montre bien l'avantage de cette méthode. Car en fait la fameuse fonction template read() super générique super top ... et bien elle se vautre si on lui passe une chaine (char*) en premier paramètre car la taille calculée va être un sizeof du pointeur et pas de la chaine. Et du coup j'étais bien content d'avoir un switch-case permettant de finement discerner le cas ASCII et d'appeler dans ce cas une fonction read spéciale prenant par exemple un char* et une taille en paramètre.

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Bonjour à tous et merci tout d'abord de votre aide.

    @darkman19320 : J'ai cru que ta solution était magique et je comprenais pas comment c'était possible. Je suis pas sûre de pouvoir intégrer BOOST au projet mais je comptais le faire jusqu'à avoir vu la faille à ta solution.
    La ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef boost::variant<int, long, double, float> Types;
    Je pensais au début que cela se traduisait par "Types peut être un int, long, double ou float" mais dans ce cas c'est vraiment magique comme truc. Je pense que c'est plus "Types va être un int, long, double et ensuite float". Et cela me convient pas du tout vu que je ne sais pas à la compilation combien de variables et de quel type vont être créées !

    @Astraya : Alors la c'est plus simple, j'ai regardé en diagonal et je n'ai rien compris Si il n'y a pas de solution plus simple je m'y pencherai plus sérieusement.

    @Arzar : Hélas non. L'utilisateur peut créer une variable en choisissant un type (enum TYPE_CODAGE) et une taille d'accès. Donc imaginons que l'utilisateur veuille créer un entier signé de 4 octet ayant pour valeur 42. Cet entier va être stocké valeur.tInt d'une sData. tInt fait 8 octets (le maximum pour une variable), c'est bien ça passe pour stocker notre petit entier (il y a même 4 octets de vide). Le problème c'est que quand on utilise la fonction write (qui ressemble beaucoup à la fonction read sauf qu'elle écrit en mémoire au lieu de lire hein !), bah à la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const size_t size = sizeof(T);
    size vaut 8 alors que je veux écrire que les 4 octets de mon petit entier.
    Bien entendu, impossible de passer la size à écrire ou lire en paramètre. C'est pour cela que la solution de la structure template est bien car si l'utilisateur veut créer un entier de 4 octets je fais
    et aucun souci de taille.

  6. #6
    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
    Juste pour info, boost.variant est implémenté exactment comme ta solution numéro 2 c'est à dire que boost::variant<int, float, double> est en fait une struct contenant un tag (un entier) + une union des types {int, float et double}, donc ça ne résoudra pas ton problème.

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    Effectivement..

  8. #8
    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
    Ton problème, c’est seulement la sérialisation ?

    Parce que dans ce cas, c’est à ce niveau que je règlerai le problème. Ta solution avec l’union me semble très bien.

  9. #9
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    C'est vrai que mon exemple donne dans l'ordre d'instanciation mais comme tu peux le voir dans ce nouvel exemple, tu peux les insérer dans n'importe quel ordre:

    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
     
    #include <iostream>
    #include <string>
    #include <vector>
     
    #include <boost/variant.hpp>
    using namespace std;
     
    template <typename Type>
    struct sData
    {
     
        enum{accessSize = sizeof(Type)}; // la taille réellement utilisée en mémoire par Type (en bytes ;) )
        Type original; // la valeur d'origine (dans son type d'origine)
    };
     
    template <typename Type>
    ostream& operator<<(ostream& os, const sData<Type>& data)
    {
      os << data.original;
      return os;
    }
     
    int main(int argc, char **argv)
    {
     
      sData<int> d1;
      d1.original = 1;
      sData<double> d2;
      d2.original = 1.23;
     
      typedef boost::variant<int, double, sData<int> > Types;
     
      vector<Types> v;
      v.push_back(1);
      v.push_back(d1);
      v.push_back(2.2);
      v.push_back(1);
    //  v.push_back(d2); //On ne peut pas mettre d'objet de type sData<double>
     
      for (int i=0; i< (int)v.size(); ++i)
        {
          cout << v[i].type().name() << endl;
          cout << v[i] << endl;
        }
      return 0;
    }
    Tu peux même récupérer le type de l'objet courant donc je ne suis pas sûr que ta structure sData te serve encore.

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    @ white_tentacle :
    Merci mais peut tu en dire un peut plus?
    Comment je fais avec la solution de l'union pour pouvoir utiliser la fonction read ou write (je donne je code s'il faut) ?

  11. #11
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2011
    Messages : 91
    Points : 48
    Points
    48
    Par défaut
    @ darkman19320 :
    Donc ça voudrait dire que je fais un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef boost::variant<sData<int8_t>, sData<uint8_t>, sData<int16_t>, sData<uint16_t>, sData<int32_t>, sData<uint32_t>, sData<int64_t>, sData<uint64_t>, sData<float>, sData<double>> > Types; // En gros à peu près tous les types possibles :mouarf:
    Et ensuite je peux instancier et push_back des structures sData de tout type template ?

  12. #12
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Oui tout à fait.

    Après je ne sais pas vraiment si la place mémoire occupée est optimale par contre.

  13. #13
    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
    Il faut que tu spécialise read pour ton union, et que tu fournisses une classe de traits qui donne la taille de tes TYPE_CODAGE.

    par exemple :
    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
     
    void read(Type val, const unsigned char* data, bool big_endian = true)
    {
    	const size_t size = type_codage_size_of<val.type>::value;
    	char*ptr = reinterpret_cast<char*>(&val);
    	for (size_t i = 0; i < size; ++i)
    		ptr[big_endian ? size - i - 1 : i] = data[i];
    }
     
    // avec
     
    template<int n>
    struct type_codage_size_of
    {
        static const int value = sizeof(long long); // par défaut, on met la valeur de long long
    }
     
    template<>
    struct type_codage_size_of<TYPE_CODAGE::ENT>
    {
       static const int value = sizeof(int);
    }
    // etc…

Discussions similaires

  1. [XSLT] Problème avec apply-templates
    Par NeoMan dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 29/12/2005, 14h45
  2. liste chainee + templates
    Par slim dans le forum C++
    Réponses: 11
    Dernier message: 10/05/2005, 19h20
  3. Réponses: 2
    Dernier message: 21/01/2005, 12h55
  4. Problème liste d'affichage
    Par nicolas66 dans le forum OpenGL
    Réponses: 6
    Dernier message: 06/12/2004, 10h10
  5. [JSP]Problème liste deroulante dynamique
    Par besco dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 09/09/2004, 17h58

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