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

Langage C++ Discussion :

Templates, dependance croisée, specialisation


Sujet :

Langage C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Templates, dependance croisée, specialisation
    Bonjour,


    Je suis entrain de coder un programme ou j'utilise 2 types de données, les entiers et les flottants. Je definit ces 2 types en utilisant des templates car suivant le cas je vais avoir besoin de differents types entiers (int, gmp) et differents types flottants (double, dpe, mpfr). Donc j'ai 2 classes (j'ai zappé les methodes non relevantes):

    type_int.h
    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
     
    #ifndef Type_int_H
    #define Type_int_H
    #include "files.h" //(les headers bateaux genre iostream, std...)
    using namespace std;
    template<class F> class Type_float;
     
    template<class Z> class Type_int{
      /*...*/
     public:
     /*...*/
      template<class F> Type_int<Z> & operator=(const Type_float<F>& s);
    };
    #include "type_int.cpp"
     
    #endif
    et

    type_float.h
    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
     
    #ifndef Type_float_H
    #define Type_float_H
    #include "files.h" //(les headers bateaux genre iostream, std...)
    #include "type_int.h" 
    using namespace std;
    template<class F>
    class Type_float
    {
     /*...*/
     public:
    /* */
      template<class Z> Type_float<F> & operator=(const Type_int<Z>& s);
    };
    #include "type_float.cpp"
    #endif
    J'ai besoin d'un truc qui me permet de passer de l'un a l'autre, d'ou dépendance croisée entre les 2. j'ai donc mis type_int 'en premier', avec une forward declaration de Type_float pour qu'il me jette pas. type_float.cpp et type_int.cpp incluent tous les 2 les 2 .h, et la méthode qui m'interresse est codée de la meme manière dans les 2. Mais si tout ce passe bien pour Type_float, si je tente de specialiser le '=' de Type_int de la maniere suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<> template<> inline Type_int<double>& Type_int<double>::operator=(const Type_float<double>& s)
    {
        data= s.GetData();
        return *this;
    }
    Je me fait jeter par le compilo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    g++ -c type_int.cpp -o type_int.o -ansi - pedantic -Wall
    g++ -c type_float.cpp -o type_float.o -ansi -pedantic -Wall
    type_int.cpp: In member function 'Type_int<Z>& Type_int<Z>::operator=(const Type_float<F>&) [with F = double, Z = double]' :
    type_int.cpp:179: erreur: invalid use of undefined type 'const struct Type_float<double>'
    type_int.h:9: erreur: declaration of 'const struct Type_float<double>'
    Je compile avec g++.real (GCC) 4.1.2.

    ça fait des heures que je suis dessus, donc si quelqu'un qui s'y connait mieux que moi a une idée, je suis preneur.

    Merci d'avance

  2. #2
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    J'ai ce genre de code dans mon projet (mais perso je n'utilise aucune spécialisation, donc je n'ai aucun problème).
    Où est-ce que tu met la spécialisation ? Si tu la met à la fin de type_int.h, forcément le compilateur ne pourra pas faire grand chose...
    Tu as essayé en le mettant à la fin de type_float.h ?

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    La specialisation se situe dans type_int.cpp, qui est inclus a la fin de type_int.h (template oblige).

    la placer dans type_float (.h ou cpp) semble effectivement une bonne idée, je vais essayer des demain matin (je n'ai pas acces a la machine pour l'instant)

  4. #4
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Un conseil, pour ne pas te mélanger les pinceaux entre les définitions des templates et les sources, nomme les fichiers .tpp et .cpp.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Une solution (je n'ai pas testé) :
    (j'ai la flemme d'écrire les includes guard mais faut les mettre)
    Type_float_fwd.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template<class F> class Type_float;
    Type_int_fwd.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template<class Z> class Type_int;
    Type_float_impl.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include "Type_int_fwd.h"
    template<class F> class Type_float
    {
    // blablabla
    };
    Type_float.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #include "type_int_impl.h"
    #include "Type_float.tpp"
    Type_float.tpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #include "type_int_impl.h"
    // blablablablabla
    Idem pour type_int.h et type_int.tpp.

    P.S. : pas de using namespace dans un .h !

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Merci
    J'ai testé la solution de Kalith, qui marche nickel. ça me chatouille un peu d'avoir des méthodes de type_int codées dans type_float, mais bon. Je suis entrain de regarder ce que tu proposes 3DArchi, mais il m'apparait assez clairement que je fais pas les choses proprement a l'heure actuelle, donc je prefererais d'abord me mettre 'a la norme' avant de me lancer dans ta technique.


    A l'heure actuelle dans mon projet j'ai :
    main.cpp -> un main bateau, qui recupere l'entrée et crée une instance de boulot pour travailler avec
    boulot.cpp / boulot.h (template<class Z, class F>)
    matrix.cpp / matrix.h (template<class T>)
    my_vect.cpp/ my_vect.h (template<class T>)
    type_float.cpp / type_float.h (template<class F>)
    type_int.cpp/type_int.h (template<class Z>)

    et toutes les classes ci dessus suivent le modèle suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #ifndef Type_float_H
    #define Type_float_H
    #include "files.h" //(les headers bateaux genre iostream, std...)
    #include "type_int.h" 
    //using namespace std; retiré car mal d'après le précédent message.
    template<class F>
    class Type_float
    {
     /*Attributs*/
     public:
    /* Methodes*/
    };
    #include "type_float.cpp"
    #endif
    et
    type_float.cpp
    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
    #ifndef Type_float_cpp
    #define Type_float_cpp
    #include "type_float.h"
    #include "whatever"
     
    using namespace std;
     
    /*Méthodes génériques */
     
    //Code des méthodes génériques, genre :
    template<class F> Type_float<F>& Type_float<F>::operator*=(const Type_float<F>& s)
    {
        mul(s);
        return *this;
    }
     
    /*Spécialisation double*/
     
    //Code des spécialisations pour les doubles, genre :
    template<> inline void Type_float<double>::mul(const Type_float<double>& c)
    {
      data *= c.GetData();
    }
    #endif
    Si j'ai a peu pres compris, je devrais séparer les codes 'génériques' des codes spécialisés, et donc avoir 3 fichiers par classe ? Genre :
    .h -> déclaration de la classe
    .tpp -> code des fonctions templates, inclus a la fin du .h
    .cpp -> code des spécialisations, retirer les 'templates<>' et les 'inline'

    Ou je suis completement a coté de la plaque ?

    Merci de votre aide en tout cas.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Ce que je te proposes :

    Ensuite, quand une autre classe a besoin de celle-ci sans l'instancier :
    -> include du XX_fwd.h dans sa déclaration
    -> include du XX_impl.h dans sa définition
    Si elle a besoin de l'instancier -> include du XX.h

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Et donc je laisse mes templates<> et autres inline dans les specialisations, car elles sont dans le .tpp, right ?

    ça va multiplier le nombre de fichiers tout ça

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Glacius Voir le message
    Et donc je laisse mes templates<> et autres inline dans les specialisations, car elles sont dans le .tpp, right ?

    ça va multiplier le nombre de fichiers tout ça
    Oui, mais...

    A vrai dire, je me demande déjà pourquoi vouloir absolument séparer les différents types primitifs...

    En effet, si tu viens un jour à devoir manipuler deux ou trois types différents dans un même fichier (ou pire, dans une même fonction), tu va devoir multiplier tes includes, or, l'énorme avantage des template est que le code exécutable n'est réellement créé que lorsqu'il est utilisé...

    Tu pourrais donc très bien envisager un fichier unique 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
    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
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    #ifnedef PRIMITIVES_TEMPLATE_HPP
    #define PRIMITIVES_TEMPLATE_HPP
    /* commençons par les déclarations anticipées */
    template<class T>
    class Type_int;
    template <class T>
    class Type_float;
    template <class T>
    class Type_brol;
    template <class T>
    class Type_bidule;
    /*...*/
    /* poursuivons par les définitions (et des spécialisations éventuelles) 
     * des différentes classes 
     */
    template<class T>
    class Type_int
    {
        public:
            /*...*/
        protected:
           /* ...*/
        private:
           /*...*/
    };
    template <class T>
    class Type_float
    {
        public:
            /*...*/
        protected:
           /* ...*/
        private:
           /*...*/
    };
    template <class T>
    class Type_brol
    {
        public:
            /*...*/
        protected:
           /* ...*/
        private:
           /*...*/
    };
    template <class T>
    class Type_bidule
    {
        public:
            /*...*/
        protected:
           /* ...*/
        private:
           /*...*/
    };
    /* terminons par les définitions des fonctions membres 
     * (éventuellement dans un fichier séparé inclus ici)
     */
     
    #endif // PRIMITIVES_TEMPLATE_HPP
    Finalement, ces différents types pourraient très bien être, peu ou prou, considérés comme autant de trait d'une politique unique, qui pourrait prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class U, template<class> class T>
    class MyPolicy : public T<U>
    {
        /*...*/
    };
    typedef MyPolicy<UnType,Type_int> UnTypeEntier;
    typedef MyPolicy<UnType,Type_float> UnTypeFloat;
    typedef MyPolicy<AutreType,Type_float> AutreTypeFloat;
    /*...*/
    et il n'y a donc pas forcément de raison, a priori, de les placer dans des fichiers séparés
    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

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    On diverge un poil là

    Ma principale raison pour séparer les implementations de float et int est que j'aime pas les fichiers trop long (chacun des 2 a 3 specialisations, vu le nombre de méthodes, ça chiffre vide en lignes). Ca me semblait assez naturel, surtout que les 2 sont là pour des usages distincts (le type float est beaucoup plus développé que le type int).

    En tout cas merci à tous pour votre aide, je suis bien content d'avoir vaincu (croisons les doigts) les templates. Je vais pouvoir m'attaquer aux parties fun maintenant que le squellette est fait : I/O et optimisation.

  11. #11
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Enfait j'utilise pratiquement la même structure que celle proposée par koala dans son dernier message (j'ai épuré le code pour que ça soit plus lisible) :
    types.h
    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
    #ifndef TYPES_H
    #define TYPES_H
     
    // inclure les headers standards ici 
    // #include <cmath>
    // ...
     
    template<class T> class s_int_t;
    template<class T> class s_uint_t;
    template<class T> class s_float_t;
     
    #include "int.h"
    #include "uint.h"
    #include "float.h"
     
    // Je n'ai pas de spécialisations, mais si j'en avais, je les mettrais donc ici
    // #include "int_spe.h"
    // ...
     
    #endif
    int.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<class T>
    class s_int_t
    {
        // blablabla
    };
    ... etc.

    Ensuite, je n'ai plus qu'à inclure "types.h" partout où j'ai besoin de ces types personalisés.
    Ca n'a pas vraiment de sens de les inclure séparément, vu qu'ils sont tous liés (par des constructeurs de conversion par exemple).

    PS : si tu t'en sors bien, tu peux te passer des spécialisations normalement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template<class T, class N> Type_int<T>& Type_int<T>::operator=(const Type_float<N>& s)
    {
        // Tous les Type_float<N> possèdent une méthode GetData().
        // On fait un static_cast au cas où T est différent de N.
        data= static_cast<T>(s.GetData());
        return *this;
    }
    PPS : au niveau des optimisations, vu que tu semble utiliser correctement les références constantes, activer les optimisations du compilateur peut te donner des résultats intéressants.
    Exemple : si ton Type_float<T> ne fait que des trucs du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Type_float<T> Type_float<T>::operator+(const Type_float<T>& s) const
    {
        return data + s.data;
    }
     
    Type_float<T> Type_float<T>::operator<(const Type_float<T>& s) const
    {
        return data < s.data;
    }
    // ...
    ... tu peux t'attendre à des performances similaires à celles du type T.

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

Discussions similaires

  1. specialisation de template
    Par camboui dans le forum Langage
    Réponses: 2
    Dernier message: 29/01/2009, 14h16
  2. [Template] specialisation de classe template
    Par vandamme dans le forum Langage
    Réponses: 3
    Dernier message: 19/10/2008, 14h22
  3. [Template] problème de références croisées
    Par ded jay dans le forum C++
    Réponses: 3
    Dernier message: 24/08/2008, 15h20
  4. specialisation de fonction template
    Par chubinou dans le forum Langage
    Réponses: 8
    Dernier message: 13/11/2007, 14h03
  5. Réponses: 5
    Dernier message: 29/12/2005, 21h27

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