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 :

Deux types pour une même instance


Sujet :

C++

  1. #1
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut Deux types pour une même instance
    Bonjour,

    J'ai dans un header un code semblable à celui-ci.
    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
    #ifdef USE_UNORDERED
    #include "boost/unordered_set.hpp"
    #else
    #include <set>
    #endif
     
     
    class MyClass
    {
    #ifdef USE_UNORDERED
    	typedef boost::unordered_set<SomeClass, SomeClass_hash, SomeClass_equal> MySet;
    #else
    	typedef std::set<StrEnum> MySet;
    #endif
    	MySet f_set;
     
    public:
    	MyClass():
    		f_set() {} // <-- ici f_set est vu comme un std::set<>
    	template<typename Tr>
    	void Init(Tr tr)
    	{
    		f_set.clear();// <-- ici, comme un boost::unordered_set<>
    		...
    	}
    };
    Quelque part dans un header de base la macro USE_UNORDERED est définie. En principe donc le type MySet est de type boost::unordered_set<>.
    Ailleurs dans le code j'ai une classe qui instancie MyClass, mais curieusement elle instancie le membre f_set comme étant un std::set<> et non pas comme un boost::unordered_set<>.
    Puis, plus loin dans le code, lorsque l'instance en question éxecute sa méthode MyClass::Init(tr) f_set est de type boost::unordered_set<>. Bien sûr, là ça plante.
    En bref, une même instance est tantôt d'un type tantôt de l'autre, comme si la macro USE_UNORDERED n'était pas "vue" à tout moment par le (pré-)compilateur. Et pourtant l'instantiation et le code se trouvent dans un même cpp, tous les headers étant déclarés au début.

    Je n'arrive pas à déterminer ou est l'erreur dans mon code (l'ordre de déclaration des headers par exemple), si erreur il y a...
    J'utilise visual studio 2005 et 2010, la même erreur se produisant avec les deux compilateurs. Je n'utilise pas la précompilation des entêtes.
    Merci de m'éclairer.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    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 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    c'est plus que très certainement un problème d'include qui définit ou non la macro selon l'unité de compilation.
    Préfère les définitions préprocesseur dans un tel cas, ça évitera ces soucis (properties > C/C++ > preprocessor)
    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.

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Dans le #else, ajoute temporairement un #error. Comme ça, tu devrais voir aisément dans quelles circonstances tu te trouves dans le #else.

    Sinon, une autre méthode pour débugger ça est de demander à générer uniquement la sortie du préprocesseur, et à t'armer de patience pour trouver où est le schmurtz. C'est l'option /P sous visual studio.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    JolyLoic, ça c'est une bonne idée, et le résultat est... renversant !
    Ça compile et j'ai toujours une instance tantôt std::set<> tantôt boost::unordered_set<> .
    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
    #ifdef USE_UNORDERED
    #include "boost/unordered_set.hpp"
    #else
    #include <set>
    #endif
     
     
    class MyClass
    {
    #ifdef USE_UNORDERED
    	typedef boost::unordered_set<SomeClass, SomeClass_hash, SomeClass_equal> MySet;
    #else
    	typedef std::set<StrEnum> MySet;
    #error USING STD::SET
    #endif
    	MySet f_set;
    public:
    	MyClass():
    		f_set() {} // <-- ici f_set est vu comme un std::set<>
    	template<typename Tr>
    	void Init(Tr tr)
    	{
    		f_set.clear();// <-- ici, comme un boost::unordered_set<>
    		...
    	}
    };
    J'ai donc modifié le fichier .h avec la directive #error comme suggéré. J'ai ensuite recompilé uniquement le cpp qui pose problème, puis j'ai linké le tout (sans recompiler les autres cpp).

    Bref, c'est comme si ce fichier .h était precompilé. Je ne comprends pas. Et non non je n'utilise pas du tout les entêtes précompilées.
    C'est fou ça !

  5. #5
    screetch
    Invité(e)
    Par défaut
    bah ou imais si tu recompiles pas les CPP, evidemment il mettra pas d'erreur de compilation...

  6. #6
    Membre expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Points : 3 284
    Points
    3 284
    Par défaut
    rien à voir avec le problème initial mais, pourquoi ne pas utiliser les template?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template<typename TYPE_SET>
    class MyClass {
       SET_TYPE MySet;
    ....
    ensuite en fonction des besoin de ton code tu peux soit utiliser les set standard ou les set de boost....


    avec par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    typedef boost::unordered_set<SomeClass, SomeClass_hash, SomeClass_equal> MyBoostSet;
     
    typedef std::set<StrEnum> MyStdSet;
     
     
    puis en fonction des besoins de ton code:
    .....
    MyClass<MyStdSet> obj1;
    ou
    MyClass<MyBoostSet> obj2;
    ...
    l'idée est la j'ai pas le compilo pour vérifier la syntaxe....
    bazar: http://www.improetcompagnie.com/publ...ctacles-6.html

    BÉPO la disposition de clavier francophone, ergonomique et libre: http://bepo.fr/wiki/Accueil

    Emacs Wiki: http://www.emacswiki.org/

    En attente de ce que produira: http://www.pushmid.com

  7. #7
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par screetch Voir le message
    bah oui mais si tu recompiles pas les CPP, evidemment il mettra pas d'erreur de compilation...
    C'est exprès, j'ai juste recompilé un seul cpp, celui qui me fait deux types pour une même instance. Il n'y a qu'un seul cpp qui utilise cette classe spécifique.
    La compilation des cpp, quand on n'utilise pas les entêtes précompilées, est complêtement indépendante entre les cpp et recompile tous les h qui en dépendent, non ?

    Jabounet, non, plus loin dans le code il y a un rehash() qui n'existe pas dans std::set<>.
    De toutes façons c'est du code transitoire, le but est de remplacer tous les set<> par des unordered_set<> quand c'est possible et opportun.

  8. #8
    Membre expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Points : 3 284
    Points
    3 284
    Par défaut
    Citation Envoyé par camboui Voir le message

    Jabounet, non, plus loin dans le code il y a un rehash() qui n'existe pas dans std::set<>.
    De toutes façons c'est du code transitoire, le but est de remplacer tous les set<> par des unordered_set<> quand c'est possible et opportun.

    Il y'a la possibilité de jouer avec les trait et policies pour indiquer que rehash est utilisable ou non.

    http://alp.developpez.com/tutoriels/traitspolicies/
    bazar: http://www.improetcompagnie.com/publ...ctacles-6.html

    BÉPO la disposition de clavier francophone, ergonomique et libre: http://bepo.fr/wiki/Accueil

    Emacs Wiki: http://www.emacswiki.org/

    En attente de ce que produira: http://www.pushmid.com

  9. #9
    screetch
    Invité(e)
    Par défaut
    non, non, non, non et non...

    on compile pas des fichiers headers des fois avec un code, des fois avec un autre... ou alors on compile un fichier, on change un truc et on compile un autre fichier.

    La compilation du projet doit etre vue comme une seule entite, on compile tous les CPP un par un puis on les lie ensemble. Si tu omets la partie linking (ce que tu fais en recompilant un fichier seulement) alors il arrive des choses surprenantes (ce qui t'arrive en ce moment)


    en l'occurrence tu as deux versions de la meme classe, une qui a un std::set et une qui a un boost::set.
    Deux versions au meme nom, aux memes signatures (puisque ce ne sont pas des parametres)

    ce qui se passe donc, c'est que tu vas instancier ta classe une fois avec std::set. TEs methodes sont inline, mais en Debug (ou des fois en release) le inline est ignore et le compilateur genere la fonction et ajoute cette methode dans ton fichier objet. Mettons que tu appelles MyClass() depuis un fichier qui utilise std::set, alors le compilo genere la version avec std::set

    ensuite dans un autre fichier, tu utilises MyClass avec un boost::set, et la le compilateur genere une deuxieme version avec boost::set.
    Les methodes etant inline, il est autorise de les avoir definies plusieurs fois; le linker se charge de faire le nettoyage en selectionnant une des versions. Bien sur, la supposition du linker c'est que t'as pas bidouille la methode entre deux fichiers et qu'il peut donc choisir n'importe laquelle des deux.
    Il en choisit une, et donc, ca devient la seule methode MyClass::MyClass() disponible pour tout l'executable. En effet, il ne peut pas y avoir de definition multiples dans un programme, donc le compilateur doit en choisir une.

    Et donc une fois sur deux il appelle la bonne methode, et une fois sur deux la mauvaise.




    Consequence: faire un systeme de build qui tient compte des dependences, ne pas recompiler un seul fichier C++, et si tu utilises des macros pour certaines classes, elles dpoivent etre definies pour tout le projet, car ta classe n'existe qu'en un seul exemplaire dans l'executable.



    Ou alors, comme jabbounet le dit, une classe template, qui elle est fait pour ca et a le droit d'exister en plusieurs exemplaires dans le code.

  10. #10
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Je répête. Le code préprocesseur est là pour assurer une transition. Les std::set<> sont utilisés sous MSVC6, sinon ce sont les unordered_set<>.

    Et puis, j'ai compilé un seul cpp pour mettre en évidence le phénomène en utilisant l'actuce suggérée par JolyLoic (#error). J'ai bien sûr relancé l'éditeur de lien après pour avoir un nouvel .exe.

    Screetch, il me semble que tu donnes les éléments de réponse, merci.
    Mais comment donc fonctionnent exactement un complilateur et un éditeur de lien ?
    Exemple:
    code1.cpp contient #include head.h et en utilise du code,
    code2.cpp contient aussi #include head.h mais n'utilise pas son code,
    head.h contient du code inline (que l'on suppose développé en appel de fonction normal).
    Le compilateur génère respectivement code1.obj et code2.obj.
    Où se trouve le code compilé de head.h ?
    Que fait ensuite l'éditeur de lien si ce code n'est appelé en pratique que par code1.cpp ? Pourquoi irait-il le chercher dans code2.obj ?

  11. #11
    screetch
    Invité(e)
    Par défaut
    et si tu recompiles *tous* les CPP, est-ce qu'il y en a un qui genere une erreur?

  12. #12
    screetch
    Invité(e)
    Par défaut
    si code2.cpp n'appelle aucun code il n'y a aucun interet a inclure le fichier header. Mefie toi du code genere automatiquement qui va aussi forcer la generation de quelques methodes (le destructeur ou la recopie par exemple).

    so code2.cpp n'instancie pas de code, probablement aucune methode n'est ajoutee dans l'executable, mais a mon avis quelques methodes snt en doubles quand meme.

    si code1.cpp utilise le constructeur, et code2.cpp utilise aussi le constructeur, alors code1.obj contient une copie du constructeur et code2.obj contient une seconde copie.

    Au link, le linker va d'abord lister toutes les fonctions dont il va avoir besoin puis il prendra la premiere version qu'il a rencontree (a mon avis) (mais ca pourrait etre la derniere ou la 41eme avant la moitie si ca lui fait plaisir, il n'y a pas de garantie)
    en plus l'ordre des methodes qu'il trouve depend de ta ligne de commande

    je repete donc qu'il faut essayer en recompilant tous les CPP (il suffit d'un CPP peut-etre pour generer une mauvaise version du code) et s'assurer que la macro est definie dans tous les objets, pas ce que tu pense etre le set minimal des fichiers qui ont besoin de definir la macro.

  13. #13
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Si je recompile tous les .cpp la directive #error se fait remarquer bien sûr.

    Dans mon head.h d'origine, il y a plusieures classes, raison pour laquelle il est inclus dans de nombreux .cpp.

    Mais seule une classe pose problème (celle du premier post) et elle n'est instanciée qu'une fois dans un seul .cpp. C'est pourquoi j'ai fait l'essai en ne recompilant que ce .cpp-là.

    Mais justement, en faisant de la sorte, on met en évidence ce que tu soupçonnes, c'est-à-dire le code de tous les .h est compilé pour chaque .cpp, même si non instancié dans chaque .cpp.
    Et comme tu dis, le linker lie le tout à sa manière en choisissant à droite ou gauche. AMA un message sur la console du linker affichant ses choix serait bienvenu (sans nécessairement avoir le niveau d'un warning).

  14. #14
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Je complète.

    Quand, nous, programmeurs on dédouble une fonction de même signature dans 2 cpp différents, le linker génère une erreur et refuse de lier.
    Quand c'est le compilateur qui dédouble les fonctions inline (ce qui doit arriver très souvent), le linker ne dit rien...

  15. #15
    screetch
    Invité(e)
    Par défaut
    ce n'est pas forcement toutes les methodes; c'est le constructeur. La methode Init est generee correctement.

    Bref, ta macro devrait etre soit definie dans le fichier lui-meme pour que tous les fichiers inclus voient la bonne valeur, soit comme option de compilation.

    Une autre possibilite c'est que ta macro doivent etre definie a 0 ou 1, et si quelqu'un inclus le fichier sans avoir defini une erreur soit generee:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #ifndef USE_UNORDERED
    # error define USE_UNORDERED to 0 ir 1 before including this file
    #endif
     
    #if USE_UNORDERED == 1
    # include "boost/unordered_set.hpp"
    #else
    # include <set>
    #endif

    j'ai l'impression que malgre mes 4 "non" dans mon message precedent tu n'as pas realise la cradocité de ce que tu essayes de faire et que tu continues a blamer le compilateur pour ne pas comprendre ton coup tordu.

  16. #16
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par camboui Voir le message
    Je complète.

    Quand, nous, programmeurs on dédouble une fonction de même signature dans 2 cpp différents, le linker génère une erreur et refuse de lier.
    Quand c'est le compilateur qui dédouble les fonctions inline (ce qui doit arriver très souvent), le linker ne dit rien...
    et si ta methode est marquee inline, il hurle?

  17. #17
    Membre expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Points : 3 284
    Points
    3 284
    Par défaut
    Citation Envoyé par camboui Voir le message
    Jabounet, non, plus loin dans le code il y a un rehash() qui n'existe pas dans std::set<>.
    Cela n'est pas génant, il y'a des moyens de s'en sortir.
    Ci dessous un exemple en utilisant des template qui permet à une class C d'appeler une methode si elle est définie pour une classe.

    Il suffit de remplacer A,B et et C par tes classes de set la method multiplyby2 par rehash et tu as l'application possible pour ton programme.

    Ici:
    Deux classes A et B sont définie avec une methode multiplyBy2 qui n'est définie que dans A.
    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
    class A {
    public:    
        A(int value_) : _value(value_) { }
     
        void print() const { printf("A=%d\n",_value); }
        void multiplyBy2() const { printf("A can be multiplied by 2: 2xA=%d\n",_value*2);  }
     
    private:
        int _value;
    };
     
    class B {
    public:    
        B(int value_) : _value(value_) { }
     
        void print() const { printf("B=%d\n",_value); }
     
    private:
        int _value;
    };
    Ici la specialisation de template permet d'appeller la methode multiplyBy2 qui n'est définie que dans A.
    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
    template <typename T> 
    struct MultiplyBy2
    {
        static const bool enabled = false;
        static void multiplyBy2(const T &t_) {};
    };    
     
    template<>
    struct MultiplyBy2<A>
    {
        static const bool enabled = true;
        static void multiplyBy2(const A & a_) {
            a_.multiplyBy2();
        }
    };
    Ici la class C peut utiliser indiférement A ou B et appeler multiplyBy2 quand la methode existe.
    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
    template<class T>
    class C {
    public:
     
        C(const T& t_): _class(t_) {}
     
        ~C() {}
     
        void doSomething() const {
     
            _class.print();
     
            if (MultiplyBy2<T>::enabled == true)
                MultiplyBy2<T>::multiplyBy2(_class);
        }
     
    private:
        T    _class;
    };
    L'exemple d'utilisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main()
    {
        C<A> myA(A(5));
        C<B> myB(B(5));
     
        myA.doSomething();
        myB.doSomething();
     
        return EXIT_SUCCESS;
     
    }
    et les traces à l'écran:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A=5
    A can be multiplied by 2: 2xA=10
    B=5

    Citation Envoyé par camboui Voir le message
    De toutes façons c'est du code transitoire, le but est de remplacer tous les set<> par des unordered_set<> quand c'est possible et opportun.
    j'ai souvent vu du transitoire durer plus longtemps que prévu.
    bazar: http://www.improetcompagnie.com/publ...ctacles-6.html

    BÉPO la disposition de clavier francophone, ergonomique et libre: http://bepo.fr/wiki/Accueil

    Emacs Wiki: http://www.emacswiki.org/

    En attente de ce que produira: http://www.pushmid.com

  18. #18
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Merci pour l'exemple jabbounet, mais le code transitoire est un code soumis à différents compilateurs, dont MSVC6 qui ne supporte pas les unordered_set<>. Sans compter une syntaxe template réduite.

    Screetch, j'ai bien compris que le code litigieux a évolué dans le temps avec les contraintes, les erreurs, les mauvaises habitudes, etc, que cela implique. J'essaie maintenant de comprendre ce que fait l'éditeur de lien avec ce que le compilateur lui fournit.

    Sinon, c'est bon, j'ai compris qu'un #define trainait quelque part, mais qu'il n'était pas propagé correctement.

    Voici cependant un code qui essaie de reproduire une situation tordue comparable (mais pas la même).

    base.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
    #ifndef _BASE_H_
    #define _BASE_H_
     
    #if defined(_MSC_VER)
    # define IS_MSVC _MSC_VER
    # if !defined(IS_MSVC_6) && (IS_MSVC<1300)
    #   pragma warning( disable : 4786 )
    #   define IS_MSVC_6
    # endif
    #else
    # error "unknown compiler"
    #endif
     
    #endif
    pre.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #ifndef _PRE_H_
    #define _PRE_H_
     
    #include "base.h"
     
    #if !defined(IS_MSVC_6)
    #define USE_SOMETHING
    #endif
     
    #endif
    pre1.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #ifndef _PRE1_H_
    #define _PRE1_H_
     
    #include "base.h"
     
    void dopre1();
     
    #endif
    pre2.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
    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
    #ifndef _PRE2_H_
    #define _PRE2_H_
     
    #include "base.h"
    #include <iostream>
     
    #ifdef USE_SOMETHING
    #include <vector>
    #else
    #include <list>
    #endif
     
    struct Tr1
    {
    	static void display()
    	{
    		std::cout << "I am Tr1" << std::endl;
    	}
    };
     
    struct Tr2
    {
    	static void display()
    	{
    		std::cout << "I am Tr2" << std::endl;
    	}
    };
     
    class MyClass
    {
    #ifdef USE_SOMETHING
    	typedef std::vector<int> MyContainer;
    #else
    	typedef std::list<int> MyContainer;
    #endif
    	MyContainer f_container;
     
    public:
    	MyClass():
    		f_container() {}
    	template<typename Tr>
    	void Init(Tr tr)
    	{
    		f_container.clear();
    		Tr::display();
    #ifdef USE_SOMETHING
    		std::cout << "I use a std::vector<>" << std::endl;
    #else
    		std::cout << "I use a std::list<>" << std::endl;
    #endif
    	}
    };
     
    void dopre2();
     
    #endif
    pre1.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "pre1.h"
    #include "pre2.h"
     
    void dopre1()
    {
    	Tr1::display();
    	Tr2::display();
    #if 1
    	MyClass mc;
    	mc.Init(Tr1());
    	mc.Init(Tr2());
    #endif
    }
    pre2.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "pre.h"
    #include "pre2.h"
     
    void dopre2()
    {
    	MyClass mc;
    	mc.Init(Tr1());
    	mc.Init(Tr2());
    }
    entry.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "pre1.h"
    #include "pre2.h"
     
    int main()
    {
    	dopre1();
    	dopre2();
    	return 0;
    }
    Sur ma machine, quand je debogue dopre2() (qui se trouve dans pre2.cpp), le conteneur dans MyClass est un std::vector<>.
    Je modifie ensuite pre1.cpp (et uniquement lui, en remplaçant #if 1 par #if 0.
    pre1.cpp est recompilé mais pre2.cpp ne l'est pas (c'est logique). L'éditeur de lien refait un nouvel executable.
    Cette fois, quand je debogue dopre2() (qui se trouve dans pre2.cpp et qui n'a pas été recompilé), le conteneur dans MyClass est un std::list<>.

  19. #19
    Membre expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Points : 3 284
    Points
    3 284
    Par défaut
    MSVC6
    Si c'est msvc6 je comprend, on a quelques applis qui l'utilisent encore chez nous aussi....
    bazar: http://www.improetcompagnie.com/publ...ctacles-6.html

    BÉPO la disposition de clavier francophone, ergonomique et libre: http://bepo.fr/wiki/Accueil

    Emacs Wiki: http://www.emacswiki.org/

    En attente de ce que produira: http://www.pushmid.com

  20. #20
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Si c'est pour être à l'échelle de tout le projet, tu devrais définir ta macro dans les options du projet.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Mesure avec deux clés pour une même dimension
    Par sniperpro dans le forum Conception/Modélisation
    Réponses: 9
    Dernier message: 29/10/2013, 17h31
  2. Réponses: 3
    Dernier message: 22/04/2013, 12h07
  3. Deux jars pour une même module EJB
    Par krum dans le forum Wildfly/JBoss
    Réponses: 0
    Dernier message: 09/11/2009, 15h15
  4. Réponses: 5
    Dernier message: 30/01/2007, 13h23
  5. [POO] Deux constructeurs pour une même classe
    Par amika dans le forum Langage
    Réponses: 4
    Dernier message: 16/12/2006, 16h31

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