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 :

Fils d'une classe template


Sujet :

C++

  1. #1
    Membre émérite

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Points : 2 328
    Points
    2 328
    Par défaut Fils d'une classe template
    Bonjour à tous

    J'ai créé une classe template qui possède une méthode static (car je veux pouvoir l'appeler sans instancier d'objet de la classe) que je définit par spécialisation comme suit :

    classe_template.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 CLASS_TEMPLATE_H
    #define CLASS_TEMPLATE_H
     
    template < typename T > class MyClass{
    	public :
    		MyClass(T a, T b):c(a),c2(b){};
    		static void foo3();
    	protected :
    		T c;
    		T c2;
    };
     
    template < >
    void MyClass<float>::foo3(){}
    template < >
    void MyClass<int>::foo3(){}
    Maintenant je souhaite créer une classe fille de MyClass<int>. Voici mon class2.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #ifndef CLASS2_H
    #define CLASS2_H
     
    #include "class_template.h"
     
    class ClasseFille : public MyClass<int> {
    	public :
    		ClasseFille(int a, int b):MyClass<int>(a,b){};
    };
     
    #endif /* CLASS2_H */
    et le main.cxx se présente ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include "class2.h"
    #include "class_template.h"
     
    #include <iostream>
    #include <string>
     
    int main( int argc, char* argv[] ){
    	ClasseFille Obj(3,4);
    	std::cout << "OK" << std::endl;
    }
    Mon code étant gros (ceci n'étant qu'une toute petite partie du code que je développe), je compile avec cmake. Mon CMakeList.txt est on ne peut plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    project(classe_template.out)
     
    add_executable(classe_template.out 
    	main.cxx
    )
    Jusque là on a une base qui marche. Maintenant ce qui ne fonctionne pas. Maintenant je veux développer un peu ma classe fille.
    Je créé donc un class2.cxx qui ne contient seulement (le but étant d'y mettre la définition de méthode ensuite) :
    Dans mon CMakeList.txt, je rajoute donc le fichier class2.cxx à la liste des sources :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    project(classe_template.out)
     
    add_executable(classe_template.out 
    	main.cxx
    	class2.cxx
    )
    Sauf que là ca ne compile plus .... (crash lors de l'édition de lien)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    duplicate symbol __ZN7MyClassIfE4foo3Ev in:
        CMakeFiles/classe_template.out.dir/main.cxx.o
        CMakeFiles/classe_template.out.dir/class2.cxx.o
    duplicate symbol __ZN7MyClassIiE4foo3Ev in:
        CMakeFiles/classe_template.out.dir/main.cxx.o
        CMakeFiles/classe_template.out.dir/class2.cxx.o
    ld: 2 duplicate symbols for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    Donc visiblement la définition de foo3 est en double.
    Mais justement je croyais que la présence de #ifndef ... #define ... permettait de parer ce genre de problème ...
    Quelqu'un peut-il déjà m'expliquer pourquoi j'ai cette erreur ?
    A part ne pas créer de class2.cxx et tout mettre dans le .h (qui rendrait juste mon code inbuvable), ai-je une autre solution ?

    Merci pour votre aide

    Edit: Précision : je compile avec cmake version 3.0.2 et Apple LLVM version 5.1 (clang-503.0.40). Mon code est en C++03.

  2. #2
    Membre confirmé Avatar de KsassPeuk
    Homme Profil pro
    Ingénieur Chercheur
    Inscrit en
    Juillet 2013
    Messages
    138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Chercheur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2013
    Messages : 138
    Points : 635
    Points
    635
    Par défaut
    Lu'!

    C'est dû au fait que tes fonctions template sont ajoutées à deux fichiers CPP différents. De cette manière on se retrouve avec deux fichiers cpp qui vont compiler chacun leur version de "foo3" pour chaque type que tu as défini. Et donc à l'édition des liens, les fonctions existeront dans plusieurs .o différents : on ne sait pas lesquelles prendre.

    Pour palier à ça, tu peux déclarer les fonctions en question inline :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template < >
    inline void MyClass<float>::foo3(){}
    template < >
    inline void MyClass<int>::foo3(){}
    Ce qui fait qu'elle ne seront pas compilées en tant que fonction (elles ne généreront pas de symbole à linker).

  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 186
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 186
    Points : 17 126
    Points
    17 126
    Par défaut
    par contraste, la garde d'inclusion (#ifndef CLASS_TEMPLATE_H ... #define CLASS_TEMPLATE_H ...#endif) protège contre la double inclusion dans la même unité de compilation.

    Par exemple, <string> peut être incluse par <iomanip> et <iostream>. Du coup, quand tu inclues ces deux derniers, tu as deux inclusions de <string>. La garde protège contre cela.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Salut,

    il faut que tes spécialisation soient inline, ou bien implémentées dans un .cpp .
    Comme toutes les fonctions non-template de classe en fait.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Membre émérite

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Points : 2 328
    Points
    2 328
    Par défaut
    Merci pour vos réponses rapides.

    La simplicité de celles-ci montre que j'ai encore du chemin à faire avant d'être un fin connaisseur de ce langage.
    M'enfin le fait d'avoir perdu plus d'une demi-journée là dessus va certainement m'aider à ne pas oublier la prochaine fois !
    C'est un codant qu'on devient codeur.

    Merci encore.

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

Discussions similaires

  1. Définition de méthodes pour une classe template
    Par Pragmateek dans le forum Langage
    Réponses: 13
    Dernier message: 20/12/2008, 01h46
  2. Class interne dans une classe template
    Par MatRem dans le forum Langage
    Réponses: 26
    Dernier message: 15/06/2006, 11h45
  3. Probleme avec une class template
    Par lenectar dans le forum Langage
    Réponses: 2
    Dernier message: 01/03/2006, 11h49
  4. Réponses: 4
    Dernier message: 08/11/2005, 16h10
  5. Trouver le Type d'une classe template dynamiquement ?
    Par Serge Iovleff dans le forum Langage
    Réponses: 3
    Dernier message: 23/09/2005, 17h48

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