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 de template (encore..)


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    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
    Par défaut Problème de template (encore..)
    Bonjour à tous,

    comme mentionner dans le titre j'ai un problème de template via un code qui m'a été donné sur ce forum (et que j'ai complété):

    j'ai une structure qui définit une variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct var
    {
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    unsigned int accessSize //taille de ma variable
    unsigned int address //adresse de la variable
    unsigned int msb //rang du msb
    unsigned int lsb //rang du lsb
    }
    Et une méthode template pour lire en mémoire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ttemplate <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;
    }
    Avec cette méthode on lit de la taille du type qui contient la valeur de la variable et non de l'accessSize de la variable. J'ai donc essayé de refaire cette méthode template pour avoir ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T>
    void readn(T& val, const char* data, int msb, int lsb, int size, bool big_endian=true)
    {
        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 <<= size * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Mais j'ai eu une erreur de compilation ligne 4 (cannot appear in a constant-expression)
    Donc quelqu'un m'a dit de faire ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T, size_t SIZE>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        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 <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    C'est cool ca compile ! Le probleme c'est que qu'on l'appelle 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
    14
    int main()
    {
        unsigned char data[1];
        data[0] = 127;
     
        var variable;
        variable.val = 0;
        variable.accessSize = 1;
        variable.msb = 7;
        variable.lsb = 0;
        variable.address = 0;
        readn<uint64_t, 1/* EN DUR BERK*/>(variable.val, data, variable.msb, variable.lsb, true);
        return 0;
    }
    Mais moi je veux pas lire d'une taille écrite en dur mais d'une taille contenue dans une variable !
    Une genre de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    readn<uint64_t>(variable.val, data, variable.msb, variable.lsb, variable.accessSize, true);
    //OU
    readn<uint64_t, variable.accessSize>(variable.val, data, variable.msb, variable.lsb, true);
    Si quelqu'un a une solution, ce serait sympa.
    Merci d'avance.

  2. #2
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    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 readn(T& val, const char* data, int msb, int lsb, int size, bool big_endian=true)
    {
        typedef typename unsigned_<size>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < size; ++i)
            ptr[big_endian ? size - i - 1 : i] = data[i];
        binary(val);
        val <<= size * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    A quoi sert la ligne 4 avec le typedef ? Tu ne l'utilises pas dans le reste de la fonction, autant la supprimer non ?

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Tu dois considérer que les paramètres template doivent obligatoirement être connus à la compilation.

    Tu peux transmettre, au moment de l'exécution, une valeur connue à la compilation comme argument à une fonction qui attend cette valeur, mais tu ne peux pas faire l'inverse.

    Ca, c'est pour l'explication "rapide" de la raison de ton erreur de compilation

    Ceci dit, pour éviter le recours à l'indication de la taille en dur, tu peux utiliser l'opérateur sizeof() qui renvoie une constante de compilation.

    Dans ton cas, tu pourrais donc t'en sortir avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int main()
    {
        unsigned char data[1];
        data[0] = 127;
     
        var variable;
        variable.val = 0;
        variable.accessSize = 1;
        variable.msb = 7;
        variable.lsb = 0;
        variable.address = 0;
        writen<uint64_t, sizeof(uint64_t)>(variable.val, data, variable.msb, variable.lsb, true);
        return 0;
    }
    (Tiens, tu as remarqué?? tu donne le code de readn mais tu essayes d'utiliser writen... enfin, le principe reste le meme )Mais il y a encore mieux à faire...

    En effet, la taille du type qui spécifie T dépend directement... du type qui spécifie T, c'est fou, ca, non

    Depuis C++11, il est possible de fournir une valeur par défaut pour les paramètres template des fonctions (en respectant la même règle que pour les valeurs par défaut des paramètres des fonctions), ce qui te permettrait, si tu profites déjà de C++11 d'avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T, size_t SIZE=sizeof(T)>
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef typename unsigned_<SIZE>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < SIZE; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Mais si tu ne profites pas encore des bienfaits de C++11, il te reste une autre solution, qui est, sommes toutes, tout aussi simpe: utiliser l'opérateur sizeof pour définir une valeur statique constante directement dans le corps de ta fonction.

    De toutes manières, étant donné que tu auras autant d'implémentation de la fonction que de type utilisé pour spécialiser T, cela ne posera aucun problème

    Cela donnerait donc quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <class T>//oui, je retire SIZE des paramètres template
    void readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        static const size_t SIZE= sizeof(T);
        typedef typename unsigned_<SIZE>::type type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < SIZE; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    Ceci dit, je ne saurais que t'inciter à envisager la création d'un foncteur (ou plutôt d'un helper qui fournirait les deux fonctions readn et writen) pour ce boulot, plutot que de garder les fonction libres.

    De manière générale, cela apporte beaucoup plus de souplesse à l'utilisation et te permettrait de n'avoir pas à passer systématiquement tous ces paramètres
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre confirmé
    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
    Par défaut
    Désolé Arzar et koala01 pour les coquilles dans mon code que j'ai tout de suite édité, on va mettre cela sous le compte de la chaleur hein et merci pour vos réponses.

    Juste koala01, je ne crois pas que tu as saisis mon problème (ou c'est qu'il n'y a pas de solution ).

    Mon type T peut être un int64_t, un uint64_t ou un double car stocke mes valeurs sur 64bits (access size maximale autorisée dans le programme) mais c'est pas parce que sizeof(T) = 8 octets que ma variable fait 8 octets ! Sa valeur est contenue dans 8octets mais sa taille est définie par la variable "accessSize" ! Et je veux pouvoir lire et écrire de cette taille la

  5. #5
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    ou c'est qu'il n'y a pas de solution
    C'est à craindre...
    Il faut pouvoir "énumérer" d'une manière ou d'une autre les différentes valeurs possibles de ta variable accessSize dès la compilation.
    J'ai un problème semblable en attente de solution élégante.
    Provisoirement je m'en tire avec un code 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
    20
    21
    22
    23
    24
    void TableRun(const std::string & outputDir, const char *tablename,
    	const char *fields, unsigned _Nsort, unsigned _Nsearch)
    {
    		GenericFmt gf;
    		gf.Init(outputDir,tablename);
    		if (1==_Nsort)
    		{
    			DirectIndexFixKey<1>(gf, fields, _Nsearch);
    		}
    		else if (2==_Nsort)
    		{
    			DirectIndexFixKey<2>(gf, fields, _Nsearch);
    		}
    		else if (3==_Nsort)
    		{
    			DirectIndexFixKey<3>(gf, fields, _Nsearch);
    		}
    		else if (4==_Nsort)
    		{
    			DirectIndexFixKey<4>(gf, fields, _Nsearch);
    		}
    		else
    			throw std::runtime_error("TableRun() unsupported _Nsort, extend code");
    }

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par DarKaa Voir le message
    Désolé Arzar et koala01 pour les coquilles dans mon code que j'ai tout de suite édité, on va mettre cela sous le compte de la chaleur hein et merci pour vos réponses.

    Juste koala01, je ne crois pas que tu as saisis mon problème (ou c'est qu'il n'y a pas de solution ).

    Mon type T peut être un int64_t, un uint64_t ou un double car stocke mes valeurs sur 64bits (access size maximale autorisée dans le programme) mais c'est pas parce que sizeof(T) = 8 octets que ma variable fait 8 octets ! Sa valeur est contenue dans 8octets mais sa taille est définie par la variable "accessSize" ! Et je veux pouvoir lire et écrire de cette taille la
    Ah, au temps pour moi, je ne l'avais pas compris comme cela...

    Ben, dans ce cas, c'est ta structure "var" que tu dois rendre template :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <SIZE>
    struct var
    {
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    enum{ accessSize = SIZE}; //taille de ma variable
    unsigned int address, //adresse de la variable
    unsigned int msb, //rang du msb
    unsigned int lsb, //rang du lsb
    };
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename TYPE>
    struct var
    {
    typedef value_type TYPE;
    uint64_t val; //valeur de ma variable (oui je stock toujours les valeurs sur 64bits)
    enum{ accessSize = sizeof(value_type)}; //taille de ma variable
    unsigned int address, //adresse de la variable
    unsigned int msb, //rang du msb
    unsigned int lsb, //rang du lsb
    };
    qui seront utilisées sous une forme proche de
    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 readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<sizeof(T)> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    ou de
    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 readn(T& val, const char* data, int msb, int lsb, bool big_endian=true)
    {
        typedef var<T> var_type;
        char *ptr = reinterpret_cast<char*>(&val);
        for(size_t i = 0; i < var_type::accessSize; ++i)
            ptr[big_endian ? SIZE - i - 1 : i] = data[i];
        binary(val);
        val <<= SIZE * CHAR_BIT - msb - 1;
        val >>= lsb;
    }
    selon le choix que tu auras fait

    [EDIT]Je préférerais personnellement la deuxième solution, car elle apporte une information supplémentaire par rapport à la première: le type de la donnée que tu manipule.

    Cela te permettra, "ailleurs", le type de la donnée d'origine en cas de besoin
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Pour 1), ça ne change pas le pb initial de DarKaa, à savoir qu'il ne peut pas faire:
    si accessSize est une variable et non une constante connue à la compil.

    Je pense que DarKaa ne veut/peut pas faire ceci:
    Pour 2), à lui de dire si ça lui va. Mais si j'ai bien compris, accessSize aura une valeur de 1 à 8 non connue à la compil.

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

Discussions similaires

  1. Problème de session (encore)
    Par akapando dans le forum Langage
    Réponses: 2
    Dernier message: 23/05/2006, 16h54
  2. [xslt][Javascript] Problème de templates
    Par Dnallabar dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 03/11/2005, 11h55
  3. problème classes templates...
    Par youp_db dans le forum C++
    Réponses: 3
    Dernier message: 02/11/2005, 13h04
  4. Réponses: 3
    Dernier message: 22/03/2005, 09h13

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