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 :

Problèmes écriture de classes templates - Compatibilité VS2008 / g++


Sujet :

Langage C++

  1. #1
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut Problèmes écriture de classes templates - Compatibilité VS2008 / g++
    Bonjour,

    Encore une fois, j'ai de gros problèmes lors de l'écriture de ma classe template.

    Voici ma classe:
    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
     
    #include <list> 
    #include <map> 
    #include <string> 
    #include <typeinfo> 
    #include <cassert> 
     
    #include "Game/UnitTemplate.h" 
    #include "Game/UnitTemplateFactionList.h" 
     
    #include "Utils/Logger.h" 
    #include "Utils/Exceptions/LibraryException.h" 
     
    template <typename T> 
    class Library 
    { 
    private: 
     
        std::map < std::string, T* > entries;   /*!< */ 
     
    public: 
     
        ~Library() 
        { 
            for ( std::map< std::string, T* >::iterator itPair = entries.begin() ; itPair != entries.end() ; ++itPair ) 
            { 
                delete (itPair->second); 
            } 
     
            LDebug << "Library of " << typeid(T).name() << " free"; 
        } 
     
        void add(const std::string& name, T* const value) 
        { 
            if ( this->exists(name) ) 
            { 
                LWarning << "Library will overwrite the key '" << name << "'"; 
            } 
            entries[name] = value; 
        } 
     
        const T* get(const std::string& name)const 
        { 
            std::map<std::string, T*>::const_iterator itT = entries.find(name); 
     
            if (itT == entries.end()) 
            { 
                throw LibraryException("Element '" + name + "' not found"); 
            } 
     
            return itT->second; 
        } 
     
        bool exists(const std::string& name)const 
        { 
            if ( entries.count(name) != 0 ) 
            { 
                return true; 
            } 
     
            return false; 
        } 
     
        // template <typename T> 
        void getValues(std::list< const T* >* pListItems)const 
        { 
            for (std::map< std::string, T* >::const_iterator itItem = entries.begin() ; 
                 itItem != entries.end() ; ++itItem ) 
            { 
                pListItems->push_back(itItem->second); 
            } 
        } 
    }; 
     
    //template <> 
    //class Library<UnitTemplate> 
    //{ 
    //private: 
     
        //std::map < std::string, UnitTemplateFactionList* > entries;     /*!< */ 
     
    //public: 
     
        //~Library() 
        //{ 
            //for ( std::map< std::string, UnitTemplateFactionList* >::iterator itPair = entries.begin() ; itPair != entries.end() ; ++itPair ) 
            //{ 
                //delete (itPair->second); 
            //} 
     
            //LDebug << "Library of " << typeid(UnitTemplateFactionList).name() << " free"; 
        //} 
     
        //void add(const std::string& name, UnitTemplate* const value) 
        //{ 
            //if ( !this->exists(name) ) 
            //{ 
                //entries[name] = new UnitTemplateFactionList(); 
                //if ( entries[name] == NULL ) 
                //{ 
                    //LError << "Fail to allocate memory for UnitTemplateFactionList"; 
                    //throw std::bad_alloc("UnitTemplateFactionList allocation failed"); 
                //} 
            //} 
     
            //entries[name]->add(value); 
        //} 
     
        //const UnitTemplateFactionList* get(const std::string& name)const 
        //{ 
            //std::map<std::string, UnitTemplateFactionList*>::const_iterator itT = entries.find(name); 
     
            //if (itT == entries.end()) 
            //{ 
                //return NULL; 
            //}// ToDO throw exception ? 
     
            //return itT->second; 
        //} 
     
        //bool exists(const std::string& name)const 
        //{ 
            //if ( entries.find(name) != entries.end() ) 
            //{ 
                //return true; 
            //} 
     
            //return false; 
        //} 
     
        //template <typename T> 
        //void getValues(std::list< const UnitTemplateFactionList* >* pListItems)const 
        //{ 
            //for (std::map< std::string, UnitTemplateFactionList* >::const_iterator itItem = entries.begin() ; 
                 //itItem != entries.end() ; ++itItem ) 
            //{ 
                //pListItems->push_back(itItem->second); 
            //} 
        //} 
    //};
    Le compilateur (g++ 4.4) me donne les erreurs suivantes:
    In file included from Engine/Library.cpp:25:
    Engine/Library.h: In destructor ‘Library<T>::~Library()’:
    Engine/Library.h:51: error: expected ‘;’ before ‘itPair’
    Engine/Library.h:51: error: ‘itPair’ was not declared in this scope
    Engine/Library.h: In member function ‘const T* Library<T>::get(const std::string&) const’:
    Engine/Library.h:70: error: expected ‘;’ before ‘itT’
    Engine/Library.h:72: error: ‘itT’ was not declared in this scope
    Engine/Library.h:77: error: ‘itT’ was not declared in this scope
    Engine/Library.h: In member function ‘void Library<T>::getValues(std::list<const T*, std::allocator<const T*> >*) const’:
    Engine/Library.h:93: error: expected ‘;’ before ‘itItem’
    Engine/Library.h:94: error: ‘itItem’ was not declared in this scope
    Mon plus gros problème, c'est que je crois que ce code compile sous VS 2008.
    Je souhaite vraiment avoir un code compatible avec les deux compilateurs.

    Ce qui me chagrine, c'est que le compilateur indique comme quoi T n'est pas défini, pourtant le template <typename T>.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Salut.
    Il faut ajouter des typename.
    http://cpp.developpez.com/faq/cpp/?p...LATES_typename

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut
    Citation Envoyé par yan Voir le message
    Salut.
    Il faut ajouter des typename.
    http://cpp.developpez.com/faq/cpp/?p...LATES_typename
    En effet, on me l'avais déjà dit, et par erreur, j'ai pris une vieille version de mon code ... donc cette conversation fait un peu doublon.

    Par contre, j'ai une vraie nouvelle question, car j'ai un problème sur la spécialisation d'une fonction dans un template (et encore avec la compatibilité VS / g++)

    Voici mon code qui compile sous g++, malheureusement, il n'est pas exécuté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <char> 
        char getAs(const std::string& name)const 
        { 
            std::cout << "Using char specialisation" << std::endl; 
            std::string charString(this->get(name)); // Can throw ParameterNotFoundParamsException 
            if ( charString.size() != 1 ) 
            { 
                throw InvalidConvertionParamsException(name); 
            } 
     
            return charString[0]; 
        }
    Lorsque je suis avec VS, j'utilise cette variante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <> 
        char getAs<char>(const std::string& name)const 
        { 
            std::string charString(this->get(name)); // Can throw ParameterNotFoundParamsException 
            if ( charString.size() != 1 ) 
            { 
                throw InvalidConvertionParamsException(name); 
            } 
     
            return charString[0]; 
        }
    Qui est correctement executée, mais qui ne compile pas sous g++, pour les raisons suivantes:
    In file included from Engine/Params.cpp:25:
    Engine/Params.h:80: error: explicit specialization in non-namespace scope ‘class Params’
    Engine/Params.h:81: error: template-id ‘getAs<char>’ in declaration of primary template
    Engine/Params.h:93: error: too many template-parameter-lists
    Le code entier est 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
    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
     
    class Params 
    { 
    private: 
     
        std::map < std::string, std::string > params;   /*!< */ 
     
    public: 
     
        void add(const std::string& name, const std::string& value); 
        void remove(const std::string& name); 
     
        bool exists(const std::string& name)const; 
     
        const std::string& get(const std::string& name)const; 
     
        template <typename T> 
        T getAs(const std::string& name)const 
        { 
            std::stringstream ss (this->get(name)); // Can throw ParameterNotFoundParamsException 
            T value; 
     
            ss >> value; 
     
            return value; 
        } 
     
        template <> 
        char getAs<char>(const std::string& name)const 
        { 
            std::string charString(this->get(name)); // Can throw ParameterNotFoundParamsException 
            if ( charString.size() != 1 ) 
            { 
                throw InvalidConvertionParamsException(name); 
            } 
     
            return charString[0]; 
        } 
     
        template <typename T> 
        T getAs(const std::string& name, const T defaultValue)const 
        { 
            if ( this->exists(name) ) 
            { 
                std::stringstream ss(this->get(name)); 
                T value; 
     
                ss >> value; 
     
                return value; 
            } 
            else 
            { 
                return defaultValue; 
            } 
        } 
    };
    Merci pour votre aide
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonsoir,

    Les spécialisations doivent se faire dans un namespace pas dans une classe, sort tes spécialisations.

    A la lecture de la norme (C++2011) je dirais que c'est VC++ qui a tort, mais je n'en suis pas certain.

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut
    Merci pour la réponse.

    J'ai mis la chose suivante dans .cpp

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <> 
    char Params::getAs<char>(const std::string& name)const 
    { 
        std::cout << "Blob" << std::endl; 
        std::string charString(this->get(name)); // Can throw ParameterNotFoundParamsException 
        if ( charString.size() != 1 ) 
        { 
            throw InvalidConvertionParamsException(name); 
        } 
     
        return charString[0]; 
    }
    Et le fichier d'entête est maintenant comme suit:
    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
     
    class Params 
    { 
    private: 
     
        std::map < std::string, std::string > params;   /*!< */ 
     
    public: 
     
        void add(const std::string& name, const std::string& value); 
        void remove(const std::string& name); 
     
        bool exists(const std::string& name)const; 
     
        const std::string& get(const std::string& name)const; 
     
        template <typename T> 
        T getAs(const std::string& name)const 
        { 
            std::stringstream ss (this->get(name)); // Can throw ParameterNotFoundParamsException 
            T value; 
     
            ss >> value; 
     
            return value; 
        } 
     
        // char getAs<char>(const std::string& name)const; 
     
     
        template <typename T> 
        T getAs(const std::string& name, const T defaultValue)const 
        { 
            if ( this->exists(name) ) 
            { 
                std::stringstream ss(this->get(name)); 
                T value; 
     
                ss >> value; 
     
                return value; 
            } 
            else 
            { 
                return defaultValue; 
            } 
        } 
    };
    Cela compile (avec g++) mais il n'y a toujours pas d'appel à la fonction spécialisée.

    Les spécialisations doivent se faire dans un namespace pas dans une classe, sort tes spécialisations.
    Hum, j'ai un peu de mal à comprendre. Comme dois-je appeler le namespace ? Comment dois je écrire la fonction dans ce namespace ? Et comment faire le lien avec la classe Params, du coup ?

    (J'ai essayé des petits trucs, mais je n'ai pas trouvé la bonne chose).

    A la lecture de la norme (C++2011) je dirais que c'est VC++ qui a tort, mais je n'en suis pas certain.
    Sachant que je suis avec VS 2008 est que celui-ci n'intègre pas la norme C++2011 ... je ne suis pas sur que l'on puisse dire qu'il a tort ou raison.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #6
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Ma phrase voulait dire de faire ce que tu as fais, tu as mis la spécialisaiton dans le namespace global alors qu'avant elle était dans la classe Params.

    Pas de séparation header/cpp pour les templates (pas comme ca du moins), mets ta spécialisation après la définition de ta classe dans le header.

    En effet VS n'est pas en respect total avec la dernière norme du C++ (comme tout les compilateurs à l'heure actuelle), mais je ne crois pas que cette partie spécifique des templates ai changé, mais je peux me tromper (il faudrait vérifier dans l'ancienne norme).

  7. #7
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Ma phrase voulait dire de faire ce que tu as fais, tu as mis la spécialisaiton dans le namespace global alors qu'avant elle était dans la classe Params.

    Pas de séparation header/cpp pour les templates (pas comme ca du moins), mets ta spécialisation après la définition de ta classe dans le header.
    C'est ce que j'avais fait au début, mais comme mon Linker me dit que la fonction est définie plusieurs fois, j'avais opté pour mettre ça dans un .cpp.

    Maintenant, il faut que je fasse en sorte qu'il ne compile qu'une fonction la spécialisation :s
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  8. #8
    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 : 54
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par LittleWhite Voir le message
    C'est ce que j'avais fait au début, mais comme mon Linker me dit que la fonction est définie plusieurs fois, j'avais opté pour mettre ça dans un .cpp.

    Maintenant, il faut que je fasse en sorte qu'il ne compile qu'une fonction la spécialisation :s
    Définis ta spécialisation en tant que fonction inline
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <> 
    inline char Params::getAs<char>(const std::string& name)const 
    { 
        std::cout << "Blob" << std::endl; 
        std::string charString(this->get(name)); // Can throw ParameterNotFoundParamsException 
        if ( charString.size() != 1 ) 
        { 
            throw InvalidConvertionParamsException(name); 
        } 
     
        return charString[0]; 
    }
    Toute fonction définie dans le fichier d'en-tête doit être définie inline, que ce soit de manière implicite (parce qu'elle est définie à l'intérieur de la définition de la classe) ou explicite
    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

  9. #9
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut
    Merci beaucoup, cela a résolu mon problème de multiple inclusions
    -> La fonction spécialisée est bien appelée.

    Il faut que je test sous VS 2008, pour être sur que tout va bien.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  10. #10
    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 : 54
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Merci beaucoup, cela a résolu mon problème de multiple inclusions
    -> La fonction spécialisée est bien appelée.

    Il faut que je test sous VS 2008, pour être sur que tout va bien.
    Ce sera le cas, je peux te l'assurer

    Le mot clé inline n'a pas seulement pour objectif de demander au compilateur de remplacer l'appel de la fonction par son code binaire, mais il a aussi comme particularité de signaler à l'éditeur de liens qu'il ne doit pas s'étonner de trouver un symbole qui serait défini plusieurs fois
    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

  11. #11
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 214
    Billets dans le blog
    167
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ce sera le cas, je peux te l'assurer
    En effet, mais je voulais m'en assurer avant de mettre la discussion en résolu.

    Le mot clé inline n'a pas seulement pour objectif de demander au compilateur de remplacer l'appel de la fonction par son code binaire, mais il a aussi comme particularité de signaler à l'éditeur de liens qu'il ne doit pas s'étonner de trouver un symbole qui serait défini plusieurs fois
    Merci pour le complément d'informations
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  12. #12
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Toute fonction définie dans le fichier d'en-tête doit être définie inline, que ce soit de manière implicite (parce qu'elle est définie à l'intérieur de la définition de la classe) ou explicite

    Le mot clé inline n'a pas seulement pour objectif de demander au compilateur de remplacer l'appel de la fonction par son code binaire, mais il a aussi comme particularité de signaler à l'éditeur de liens qu'il ne doit pas s'étonner de trouver un symbole qui serait défini plusieurs fois
    Je viens de tomber sur le problème, et j'aimerais une explication mécanisme pour que je comprenne ce qu'il se passe.

    Tu sembles dire qu'il faille systématiquement mettre les fonction de template en inline.
    Sauf peut-être avec l'utilisation du mot-clé export (avec un compilateur qui l'implémente) ?

  13. #13
    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 : 54
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par oodini Voir le message
    Je viens de tomber sur le problème, et j'aimerais une explication mécanisme pour que je comprenne ce qu'il se passe.

    Tu sembles dire qu'il faille systématiquement mettre les fonction de template en inline.
    Sauf peut-être avec l'utilisation du mot-clé export (avec un compilateur qui l'implémente) ?
    oui, tout à fait...

    Pour que tu comprennes, il faut reprendre la base du principe des template:

    Les template s'utilisent parce que l'on se dit quelque chose comme
    je ne sais pas quel type de données je vais devoir utiliser, mais je sais par contre parfaitement comment je vais utiliser ces données
    On va donc décider que la donnée utiliser est "de type T", quel que soit le type réel de T.

    Seulement, le compilateur doit savoir à quoi correspond ce "type T" pour pouvoir prévoir un espace mémoire suffisant pour contenir la donnée avant de créer le code binaire correspondant:

    Un "simple" int ne prendra que quelque bytes alors qu'une structure plus complexe prendra une taille bien supérieure, et, s'il ne prend pas cette taille en compte au moment de créer le code binaire, la donnée risque fortement "d'écraser" une partie du code

    Il doit disposer du code C++ des fonctions / de la classe pour chaque utilisation!

    C'est la raison pour laquelle le code doit se systématiquement être accessible en même temps que la définition de la classe ou que la déclaration de la fonction.

    Les seules solutions pour y arriver sont
    • de placer le code dans le même fichier d'en-tête que la déclaration de la fonction ou que la définition de la classe
    • de placer le code dans un fichier qui sera inclus en même temps que celui dans lequel se trouve la déclaration de la fonction ou que la définition de la classe
    Mais il faut garder en tête le fait que le compilateur oublie systématiquement ce qu'il a fait pour un fichier lorsqu'il passe au fichier suivant!

    S'il a considéré, en compilant xx.cpp, que T == int, et qu'il retombe sur une utilisation de la classe ou de la fonction pour laquelle T == int dans yy.cpp, il ne se souvient absolument pas d'avoir déjà créé le code binaire correspondant dans xx.cpp!

    Il va donc... créer une deuxième fois le code binaire correspondant

    Pour le compilateur, il n'y aura aucun problème (pour autant que le code C++ soit correct ) mais, c'est sans compter sur le fait qu'il y a un autre outil, l'éditeur de liens, qui va manipuler le code binaire de tous les fichiers, et que ce dernier va... avoir une vue d'ensemble de tout ce qui se trouve dans tous les fichiers objets!

    Or, le symbole de la fonction qui considère que T == int sera strictement identique dans XX.o(bj) que dans YY.o(bj)!

    C'est, finalement, tout à fait normal : les règles pour définir le symbole pour une fonction sont clairement définies et s'assurent qu'une fonction ayant le même type de retour, le même nom et les mêmes arguments (en type et en nombre) produira un symbole strictement identique!

    Et là, l'éditeur de liens ne sera pas content parce qu'il ne pourra pas décider avec quel code binaire effectuer la liaison pour les appels de la fonction : doit il effectuer la liaison avec le symbole défini dans XX.o(bj) ou avec celui défini dans YY.o(bj)

    Le seul moyen pour résoudre le problème, c'est que la fonction soit déclarée (de manière implicite ou explicite) inline : l'éditeur de liens ne s'étonnera alors absolument pas d'avoir deux fois le même symbole (car il sait que le compilateur l'aura sans doute généré plusieurs fois), et il saura exactement comment réagir face à cette situation
    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

  14. #14
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Merci beaucoup pour cette explication très complète.

    J'en déduis trois choses :

    1. cette explciation devrait être dans la FAQ
    2. éviter de templatiser de grosses fonctions si elles sont souvent appelées
    3. le mécanisme de compilation du C++ aurait vraiment dû etre revu

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

Discussions similaires

  1. Avis sur un problème de "friend class template"
    Par metagoto dans le forum C++
    Réponses: 8
    Dernier message: 24/03/2010, 18h16
  2. [Template] Problème Classe Template
    Par gimpycpu dans le forum Langage
    Réponses: 7
    Dernier message: 23/05/2007, 06h10
  3. problème classes templates...
    Par youp_db dans le forum C++
    Réponses: 3
    Dernier message: 02/11/2005, 14h04
  4. Problèmes de fonctions membres de classe templates, gcc3.3.6
    Par yves.dessertine dans le forum Autres éditeurs
    Réponses: 12
    Dernier message: 17/10/2005, 22h36
  5. [DLL/classe template] problème de link
    Par Bob.Killer dans le forum C++
    Réponses: 7
    Dernier message: 31/08/2005, 19h56

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