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 :

Besoin d'aide pour contourner une internal compiler error


Sujet :

C++

  1. #1
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut Besoin d'aide pour contourner une internal compiler error
    Bonjour à tous

    Désolé pour le titre imprécis, mais pas facile d'en trouver un pour mon problème.

    Je possède une classe abstraite, nommée ici Driver, qui sert d'interface entre le programme et des API spécifiques (chaque dérivée de Driver implémente une API différente).

    Pour des raisons diverses et justifiées, je me suis codé une petite classe proxy pour cacher les appels du genre Driver->SetSomeState(true) derrière des affectations du genre Driver->SomeState = true.

    Voici un code complet minimal qui reproduit le problème (que j'explique juste après) :

    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
    class Driver;
    Driver* GlobalDriver;
     
    class Driver
    {
    private :
     
        virtual void SetSomeState(bool) {}
     
    public :
     
        template <typename T, void (Driver::*Func)(T)>
        struct State
        {
            State& operator =(T Value)
            {
                (GlobalDriver->*Func)(Value);
                return *this;
            }
        };
     
        struct States
        {
            State<bool, &Driver::SetSomeState> SomeState;
        };
     
        States TheStates;
    };
     
     
    int main()
    {
        GlobalDriver = new Driver;
        GlobalDriver->TheStates.SomeState = true;
     
        return 0;
    }
    Mon problème est que ce code est valide, mais ne compile pas (Visual C++ 8 me sort une internal compiler error, suivie d'un crash du compilateur).

    J'ai isolé le problème :

    Si les fonctions de Driver ne sont pas virtuelles cela compile, mais je suis obligé de les laisser virtuelles.
    Si la classe States est définie en dehors de Driver cela compile, mais je ne peux pas non plus le faire car toutes deux sont dépendantes l'une de l'autre.
    Je pourrais également intercaler une fonction non virtuelle entre ma classe State et l'appel à la fonction virtuelle, mais c'est exclu car je dois quoiqu'il arrive être certain qu'en mode release mon mécanisme de proxy ne laisse pas de trace (ie. soit équivalent à l'appel direct).

    J'ai trituré le code dans tous les sens, mais sans jamais réussir à le faire compiler tout en gardant des fonctionnalités identiques.

    Une idée ??


  2. #2
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    avec ton code, avec g++, j'ai :

    laurent.cpp: In member function `Driver::State<T, Func>& Driver::State<T, Func>::operator=(T)':
    laurent.cpp:17: error: `GlobalA' was not declared in this scope
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                (GlobalA->*Func)(Value);
    GlobalA correspond à quoi ?

  3. #3
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Oups, un vieux truc qui trainait. Il fallait lire GlobalDriver.

  4. #4
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    Bon, c'est définitif... change de compilateur tout simplement

    j'ai testé avec G++ sous nunux et Mingw (Dev-C++) sous Windows, et il n'y a pas de problèmes...

    il doit bien y avoir une config sous VC++ pour spécifier le compilo non ?

  5. #5
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Le problème est que mon code doit supporter Visual C++ (et j'imagine que si le 8 ne passe pas, les autres non plus).

    Bon, c'est tout de même rassurant de voir que gcc fait correctement son boulot.

  6. #6
    Membre averti
    Avatar de Foobar1329
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 283
    Points : 387
    Points
    387
    Par défaut
    Hello,

    Citation Envoyé par Laurent Gomila
    Le problème est que mon code doit supporter Visual C++ (et j'imagine que si le 8 ne passe pas, les autres non plus).

    Bon, c'est tout de même rassurant de voir que gcc fait correctement son boulot.
    Bon, j'ai lu et relu les passages de ma n1905 qui concernent l'opérateur de prise d'adresse, notamment sur les fonctions membres virtuelles, et je n'ai rien vu dedans qui pourrait empêcher de faire ce que tu fais. Le problème du compilo vient peux-être du fait qu'il ne sait pas récupérer &Driver::SetSomeState à l'instanciation du template State<bool, &Driver::SetSomeState> qui est faite quand Driver n'est pas encore complètement défini (à la définition de la structure States) . Mais là, il faut attendre l'avis d'experts du langage our se prononcer en faveur d'un bug MS ou pas, car prise d'adresse de fonction membre virtuelle pendant instanciation de classe template englobée =>

    En attendant, j'ai trouvé une solution pour compiler selon tes exigences : j'ai encapsulé la fonction virtuelle, dans une structure qui est complètement définie au moment de l'instanciation du template.

    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
    class Driver;
    Driver* GlobalDriver;
     
    class Driver
    {
    private :
     
        struct Job{
            virtual void SetSomeState(bool) {}
            virtual void SetAnotherState(bool) {}
        } jopic;
     
    public :
     
        template <typename T, void (Driver::Job::*Func)(T)>
        struct State
        {
            State& operator =(T Value)
            {
                (GlobalDriver->jopic.*Func)(Value);
                return *this;
            }
        };
     
        struct States
        {
            State<bool, &Driver::Job::SetSomeState> SomeState;
            State<bool, &Driver::Job::SetAnotherState> AnotherState;
        };
     
        States TheStates;
    };
     
     
    int main()
    {
        GlobalDriver = new Driver;
        GlobalDriver->TheStates.SomeState = true;
        GlobalDriver->TheStates.AnotherState = false;
        return 0;
    }
    A+

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Intéressant. Par contre c'est assez ugly, parce que du coup les drivers doivent hériter de Driver::Job, et par conséquent je dois y mettre toutes les fonctions à redéfinir, même celles qui ne concernent pas les états. En fait à terme c'est également impossible (niveau design de classes).

    Mais au moins ça met bien en évidence une autre des causes de l'erreur (classe pas entièrement définie). Et effectivement il serait intéressant de savoir si tout cela est bien défini par la norme, ou si je m'aventure dans un quelconque comportement aléatoire.

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Laurent Gomila
    Et effectivement il serait intéressant de savoir si tout cela est bien défini par la norme, ou si je m'aventure dans un quelconque comportement aléatoire.
    Une erreur interne est toujours un probleme du compilateur. Reporte le a MS.

    Et dans ce cas-ci, j'ai pas l'impression que c'est suite a une erreur dans le code, en tout cas tout me semble correct (ca passe avec ma collection de version de g++ et avec Sun CC).

    Des pistes -- je ne connais pas VC++ du tout -- pour essayer de contourner le probleme:
    - si j'ai bien compris, il y a different modes de gestion des pointeurs vers membres: essaie de jouer avec (en particulier le mettre sur la maniere la plus conforme)
    - essaie d'introduire une classe de base de Driver et qui servirait pour le deuxieme parametre de State
    - essaie d'ajouter un troisieme paramatre a State
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        template <typename T, typename U, void (U::*Func)(T)>
        struct State {...}

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    - si j'ai bien compris, il y a different modes de gestion des pointeurs vers membres: essaie de jouer avec (en particulier le mettre sur la maniere la plus conforme)
    Je n'ai rien trouvé de tel dans les options du compilo. Tu aurais des précisions sur cette info ?

    - essaie d'ajouter un troisieme paramatre a State
    Pas mieux.

    - essaie d'introduire une classe de base de Driver et qui servirait pour le deuxieme parametre de State
    Ca règle le problème, en effet. Au final ça me donne un code assez alambiqué pour finalement pas grand chose, mais bon il faut ce qu'il faut (je me console en regardant comment est codé boost -- c'est blindé de macros anti-bug compilateurs)

    Question subsidiaire à deux balles : la fonction membre que je passe en paramètre template est privée, hors cela ne me génère pas d'erreur ; alors qu'un passage de la même fonction en paramètre de fonction génèrerait une erreur de compilation. J'imagine que c'est conforme à la norme, mais ça ne me paraît pas logique.

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Laurent Gomila
    Je n'ai rien trouvé de tel dans les options du compilo. Tu aurais des précisions sur cette info ?
    D'après ce que j'ai compris -- je n'ai jamais utilisé un compilo de MS sérieusement -- le compilo de MS implémente une heuristique qui joue avec la taille des pointeurs vers membre, mais a une option pour forcer un comportement standard. Mais c'est peut-être plus le cas de VC++8

    Question subsidiaire à deux balles : la fonction membre que je passe en paramètre template est privée, hors cela ne me génère pas d'erreur ; alors qu'un passage de la même fonction en paramètre de fonction génèrerait une erreur de compilation.
    Je ne vois pas de problème à ce qu'un membre passe un pointeur vers une fonction membre privée.

  11. #11
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Je ne vois pas de problème à ce qu'un membre passe un pointeur vers une fonction membre privée.
    Ok, sortons de cet exemple, en voici un plus explicite :

    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
    class A
    {
        void PrivateFunc() {}
    };
     
    template <void (A::*Func)()>
    struct Test
    {
        // F passée en paramètre template de la fonction
        template <void (A::*F)()>
        void F1(A a) {(a.*F)();}
     
        ///  F passée en paramètre de la fonction
        void F2(A a, void (A::*F)()) {(a.*F)();}
     
        ///  F passée en paramètre template de la classe
        void F3(A a) {(a.*Func)();}
    };
     
    int main()
    {
        A a;
        Test<&A::PrivateFunc> t;
     
        t.F1<&A::PrivateFunc>(a); // Erreur
        t.F2(a, &A::PrivateFunc); // Erreur
        t.F3(a);                  // OK
     
        return 0;
    }

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Je ne saurais pas te citer le standard à ce sujet, mais je pense que ce n'est pas permis.
    D'ailleurs, ni g++, le compilo d'intel ne l'autorise. Les deux refusent d'instancier le template.

  13. #13
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Pour la première écriture, avec un t.template F1<...>, ça ne marche pas non plus ?

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Laurent Gomila
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        Test<&A::PrivateFunc> t;
    Ceci ne devrait pas passer. Cela passe dans ton message initial parce que le type est defini a l'interieur de A.

  15. #15
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ceci ne devrait pas passer. Cela passe dans ton message initial parce que le type est defini a l'interieur de A.
    Pourtant, une classe imbriquée n'a pas plus de "droit" sur sa classe parent que n'importe quelle autre classe, non ?

    De toute façon, le second exemple que je fournit compile également, ce qui veut dire que c'est le compilo qui n'est pas conforme.

  16. #16
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Laurent Gomila
    Pourtant, une classe imbriquée n'a pas plus de "droit" sur sa classe parent que n'importe quelle autre classe, non ?
    Il me semble que c'est un des changements de 2003. En tout cas ton premier exemple compile avec como et gcc 4.1.1 en le modifiant comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            State& operator =(T Value)
            {
                (GlobalDriver->*Func)(Value);
                GlobalDriver->SetSomeState(Value);           
                return *this;
            }
    De toute façon, le second exemple que je fournit compile également, ce qui veut dire que c'est le compilo qui n'est pas conforme.
    Je ne suis pas le dernier mot en la matiere -- surtout que j'ai pas le temps de verifier aux sources --, mais je ne suis pas le seul de cet avis:

    Citation Envoyé par http://www.comeaucomputing.com/tryitout
    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
    Comeau C/C++ 4.3.3 (Aug  6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
    Copyright 1988-2003 Comeau Computing.  All rights reserved.
    MODE:strict errors C++
     
    "ComeauTest.c", line 23: error: function "A::PrivateFunc" is inaccessible
          Test<&A::PrivateFunc> t;
                   ^
     
    "ComeauTest.c", line 25: error: function "A::PrivateFunc" is inaccessible
          t.F1<&A::PrivateFunc>(a); // Erreur
                   ^
     
    "ComeauTest.c", line 26: error: function "A::PrivateFunc" is inaccessible
          t.F2(a, &A::PrivateFunc); // Erreur
                      ^
     
    3 errors detected in the compilation of "ComeauTest.c".
    g++ dit la meme chose (mais formate moins bien pour citer).

  17. #17
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ok, merci pour toutes ces infos

  18. #18
    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 : 50
    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
    Citation Envoyé par Laurent Gomila
    Pourtant, une classe imbriquée n'a pas plus de "droit" sur sa classe parent que n'importe quelle autre classe, non ?
    En théorie, non. Par contre, j'ai déjà remarqué que c'était le cas sous visual studio 2005.

  19. #19
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    Heu, perso il m'a semblé remarquer que les classes imbriquées avaient accès au membres protected et private des classes qui les contiennent (logique dans un sens puisqu'elles font elle-même partie des membres)...

    Pour info je travail avec G++

    ensuite, peut-être que je me suis trompé...

Discussions similaires

  1. [VBA-E]besoin d'aide pour faire une boucle
    Par mikazounette dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 10/04/2006, 15h04
  2. besoin d 'aide pour formuler une requête
    Par cdu dans le forum Langage SQL
    Réponses: 2
    Dernier message: 08/04/2006, 20h38
  3. besoin d'aide pour optimiser une requête
    Par jisse dans le forum Langage SQL
    Réponses: 4
    Dernier message: 27/01/2006, 10h41
  4. Besoin d'aide pour afficher une image dans un applet
    Par argon dans le forum AWT/Swing
    Réponses: 16
    Dernier message: 19/01/2006, 20h45
  5. besoin d'aide pour intégrer une entité dans un MCD
    Par barkleyfr dans le forum Schéma
    Réponses: 17
    Dernier message: 13/10/2005, 14h29

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