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 :

Détermination automatique de paramètres de patron : erreur interne du compilateur


Sujet :

C++

  1. #1
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut Détermination automatique de paramètres de patron : erreur interne du compilateur
    Bonjour,

    Dans le code situé à la fin de ce message, j'ai une classe 'exec' template avec plusieurs paramètres. Le dernier paramètre est l'adresse d'une méthode, dont le type est déterminé par les autres paramètres. La fonction 'maker' de ce code doit, étant donné une méthode d'une classe, retourner une instance de 'exec' où les types auront été déterminés automatiquement.

    Lorsque je compile cet exemple, avec g++ 4.3 ou 4.4, j'ai l'erreur suivante :
    test_f_temp.cpp: In member function ‘void exec<C, R, A1, A2, method_name>::caller::run(base_object&) const [with C = T1, R = int, A1 = int, A2 = double, R (C::* method_name)(A1, A2) = method_name]’:
    test_f_temp.cpp:30: internal compiler error: in expand_expr_real_1, at expr.c:7314
    Please submit a full bug report,
    with preprocessed source if appropriate.
    See <file:///usr/share/doc/gcc-4.4/README.Bugs> for instructions.
    Je ne vois pas ce qui le perturbe dans le code, alors je cherche une alternative que mon compilateur apprécierait plus. Remarquez, de plus, que le problème ne se pose que pour l'appel à 'maker'. La partie concernant 'c0' dans le main() passe très bien.

    Pourriez-vous me dire si vous voyez un problème dans le code*? si ça compile bien avec votre compilateur et si vous voyez une alternative*?

    Cordialement,

    Julien

    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
    #include <iostream>
     
    class base_object
    {
    public:
      virtual ~base_object() { }
    }; // class base_object
     
    // classe mère pour la classe exec::caller ci-dessous
    class base_caller
    {
    public:
      virtual void run(base_object& i) const = 0;
    }; // class base_caller
     
    // Cette classe définit une dérivée de base_caller pour appeler une méthode de
    // la classe C, de type de retour R et dont les paramètres sont de type A1, ...,
    // An. Une instance de ce caller est crée.
    template< typename C, typename R, typename A1, typename A2,
              R (C::*method_name)(A1, A2) >
    class exec
    {
    public:
      typedef R (C::*method_type)(A1, A2);
     
    public:
      class caller:
        public base_caller
      {
      public:
        virtual void run(base_object& i) const
        {
          C& inst( dynamic_cast<C&>(i) );
          const method_type m(method_name);
          (inst.*m)(1, 0);
        }
      }; // class caller
     
      static caller instance;
    }; // class exec
     
    template< typename C, typename R, typename A1, typename A2,
              R (C::*method_name)(A1, A2) >
    typename exec<C, R, A1, A2, method_name>::caller
    exec<C, R, A1, A2, method_name>::instance;
     
    // méthode pour trouver l'instance de exec<>::instance qui convient en fonction
    // de la fonction à appeler.
    template<typename C, typename R, typename A1, typename A2>
    base_caller* maker( R (C::*method_name)(A1, A2) )
    {
      return &exec<C, R, A1, A2, method_name>::instance;
    }
     
    // petit exemple
    class T1:
      public base_object
    {
    public:
      int test( int a, double b )
      { std::cout << "T1" << std::endl; return 0; }
    };
     
    int main()
    {
      T1 t1;
     
      base_caller* c0 = &exec<T1, int, int, double, &T1::test>::instance;
      c0->run(t1);
     
      base_caller* c1 = maker( &T1::test );
      c1->run(t1);
     
      return 0;
    }

  2. #2
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Déjà, il te dit quand même que c'est une erreur du compilateur >< !

    Ensuite, j'ai l'impression qu'il a du mal a résoudre "method_name". Ca me parait normal puisque ce n'est pas un paramètre template. Est-ce que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    template<typename C, typename R, typename A1, typename A2, 
            R (C::*method_name)(A1, A2)>
    base_caller* maker( R (C::*method_name)(A1, A2) )
    {
      return &exec<C, R, A1, A2, method_name>::instance;
    }
    ne parait pas plus logique ? A mes yeux oui, mais je peux me tromper !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  3. #3
    screetch
    Invité(e)
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1>e:\test\main.cc(52) : error C2971: 'exec' : template parameter 'method_name' : 'method_name' : a local variable cannot be used as a non-type argument
    1>        e:\test\main.cc(22) : see declaration of 'exec'
    1>        e:\test\main.cc(50) : see declaration of 'method_name'
    1>        e:\test\main.cc(71) : see reference to function template instantiation 'base_caller *maker<T1,int,int,double>(R (__thiscall T1::* )(A1,A2))' being compiled
    1>        with
    1>        [
    1>            R=int,
    1>            A1=int,
    1>            A2=double
    1>        ]
    Lavock : ton code ne compile pas plus malheureusement car il ne peut pas déduire le parametre de template a partir du parametre de méthode.

  4. #4
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Merci, avec ce message d'erreur on y voit plus clair
    Citation Envoyé par screetch Voir le message
    a local variable cannot be used as a non-type argument
    En effet, le paramètre method_name est une valeur, que j'essaie de passer en paramètre au template. On n'y voit pas très clair avec la déclaration de method_name, ça sera mieux avec des entiers. En gros, c'est comme si j'avais écrit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<typename C, typename R, typename A1, typename A2, int I>
    class exec
    {
    ...
    };
     
    template<typename C, typename R, typename A1, typename A2>
    base_caller* maker( int i )
    {
      return &exec<C, R, A1, A2, i>::instance;
    }
    Et là on voit bien que j'essaie de passer une variable locale en paramètre au template, ce qui ne risque pas de fonctionner.

  5. #5
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Erf, c'est pas évident là, mais je vois pas ce qui cloche. Peut-être essayé de passer par référence de fonction plutôt ? Remarque, je vois pas pourquoi ça marcherait mieux >< !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  6. #6
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par j-jorge Voir le message

    Et là on voit bien que j'essaie de passer une variable locale en paramètre au template, ce qui ne risque pas de fonctionner.
    On peut passer une variable a une template, mais il faut que ce soit au choix:
    • un entier ou un type enuméré
    • un pointeur (objet ou fonction)
    • un lvalue ref(objet ou fonction)
    • un pointeur à un membre (<== ton cas si je ne m'abuse)
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  7. #7
    screetch
    Invité(e)
    Par défaut
    non on ne peut pas passer une variable en parametre de template on ne peut passer qu'une constante de compilation, or ce n'est pas ce que faisait l'auteur.

  8. #8
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Citation Envoyé par Lavock Voir le message
    On peut passer une variable a une template, mais il faut que ce soit au choix:
    • un entier ou un type enuméré
    • un pointeur (objet ou fonction)
    • un lvalue ref(objet ou fonction)
    • un pointeur à un membre (<== ton cas si je ne m'abuse)
    Il faut aussi que ce soit une constante connue à la compilation. Or, en passant l'adresse de la méthode en paramètre à 'maker()', on perd ce statut de constante. Imaginons que j'appelle la fonction maker(), telle que je l'ai écrite dans mon premier post, avec deux méthodes ayant la même signature. Le compilateur va définir une seule implémentation de maker(), mais le type retourné devrait être différent pour chaque méthode. Ce qui est problématique.

    Il faudrait donc que l'adresse de la méthode apparaisse dans les paramètres templates de maker(), et soit déduit du paramètre passé à l'appel. Je ne vois pas encore comment. J'ai essayé quelque chose de proche de ta première réponse, mais j'ai la même erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template< typename C, typename R, typename A1, typename A2,
              R (C::*Method)(A1, A2) >
    base_caller* maker( R (C::*method_addr)(A1, A2) )
    {
      return &exec<C, R, A1, A2, Method>::instance;
    }

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

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    En fait ce qui est étonnant c'est de vouloir mettre l'adresse de la fonction comme paramètre template. En gros, tu (re)fais un boost:function dans lequel non seulement tu captures la signature mais tu veux en plus capturer l'adresse de la fonction comme paramètre générique à la compilation là où en général on associe cette adresse dynamiquement au moment de l'exécution.

  10. #10
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Hum, si, me suis un peu planté, mais une variable peut m'être, a condition qu'elle respect un certain nombre de contrainte(pas de lvalue qui ne necessite pas de linkage, ou des temporaire).

    D'ailleurs, c'est pour ça que ma proposition devrait hypothétiquement marchait : On certifie de par ce fait que la "variable" n'en n'est pas une puisque c'est un paramètre template aussi.
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  11. #11
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par j-jorge Voir le message
    Il faudrait donc que l'adresse de la méthode apparaisse dans les paramètres templates de maker(), et soit déduit du paramètre passé à l'appel. Je ne vois pas encore comment.
    Hum, je suppose que ma proposition te sors un vieux shadowing ?

    Là ça se corse... Il faut signifier d'une manière quelconque au compilo que la variable passer et bel et bien le dernier paramètre template. Mais ça, je sais pas faire !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  12. #12
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    En fait ce qui est étonnant c'est de vouloir mettre l'adresse de la fonction comme paramètre template. En gros, tu (re)fais un boost:function dans lequel non seulement tu captures la signature mais tu veux en plus capturer l'adresse de la fonction comme paramètre générique à la compilation là où en général on associe cette adresse dynamiquement au moment de l'exécution.
    L'idée était de profiter du fait que l'adresse était connue à la compilation, pour éviter de l'associer à l'exécution. Mais je crois que je vais laisser tomber cette approche, ça devient un poil compliqué.

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

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par j-jorge Voir le message
    L'idée était de profiter du fait que l'adresse était connue à la compilation, pour éviter de l'associer à l'exécution. Mais je crois que je vais laisser tomber cette approche, ça devient un poil compliqué.
    On reste sur la macro

  14. #14
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    En fait, tu voulais juste t'économiser de la redondance, à savoir écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    &exec<T1, int, int, double, &T1::test>::instance;
    alors que toutes les infos utiles peuvent être déduites du dernier argument ?

    Je trouve l'idée sympa de façon générale => déduire des paramètres de type template par un argument non-type template aussi ! Mais j'avoue que je sèche...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  15. #15
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par j-jorge Voir le message
    L'idée était de profiter du fait que l'adresse était connue à la compilation, pour éviter de l'associer à l'exécution. Mais je crois que je vais laisser tomber cette approche, ça devient un poil compliqué.
    Si je ne me trompe pas, l'adresse est connue lors de la génération du code, et donc bien après la résolution des templates, non ?

    Sinon, il y a moyen de revenir depuis une variable à une constante de compilation en utilisant un bon vieux switch, ça marche bien pour des enums avec peu de valeurs, par contre, pour une adresse de fonction, c'est mort.

  16. #16
    screetch
    Invité(e)
    Par défaut
    c'est theoriquement possible, le code ci-dessus le fait. Mais le but de l'auteur etait de déduire automatiquement le type de la méthode sans avoir a ecrire chaque type individuellement, pour alléger la syntaxe.

  17. #17
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Si je ne me trompe pas, l'adresse est connue lors de la génération du code, et donc bien après la résolution des templates, non ?

    Sinon, il y a moyen de revenir depuis une variable à une constante de compilation en utilisant un bon vieux switch, ça marche bien pour des enums avec peu de valeurs, par contre, pour une adresse de fonction, c'est mort.
    Je confirme : c'est au mieux au moment du link que l'adresse de la méthode est connu, pas au moment de la compilation de l'unité (au pire: méthode virtuelle, donc l'adresse est connue au run time uniquement). Il n'y a donc aucun moyen de la récupérer pour la passer en paramètre à un template. La seule chose qu'on peut faire avec une fonction (membre ou non) et une classe template, c'est la déduction du type de la fonction / fonction membre.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  18. #18
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Je confirme : c'est au mieux au moment du link que l'adresse de la méthode est connu, pas au moment de la compilation de l'unité (au pire: méthode virtuelle, donc l'adresse est connue au run time uniquement). Il n'y a donc aucun moyen de la récupérer pour la passer en paramètre à un template. La seule chose qu'on peut faire avec une fonction (membre ou non) et une classe template, c'est la déduction du type de la fonction / fonction membre.
    Par curiosité, j'aimerais savoir comment le compilateur gère le code 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
    #include <iostream>
     
    template<void (*P)()>
    struct test_func
    {
      static void print() { P(); }
    };
     
    class object
    {
      void f() { std::cout << "object::f()" << std::endl; }
    };
     
    template<void (object::*P)()>
    struct test_method
    {
      static void print() { object o; (o.*P)(); }
    };
     
    void f() { std::cout << "f()" << std::endl; }
     
    int main()
    {
      test_func<&f>::print();
      test_method<&object::f>::print();
     
      return 0;
    }
    Ça n'est pas l'adresse de la méthode/fonction qui est passée aux classes templates, je suis d'accord, mais ça me semble être plus qu'un simple type, non ? Il faut bien qu'il y ait quelque chose qui permette d'effectuer l'appel dans XX::print().

  19. #19
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Il est pourtant préciser dans la norme que parmi les paramètre de template non-typé on peut mettre l'adresse d'une constante / fonction...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  20. #20
    screetch
    Invité(e)
    Par défaut
    oui, emmanuel se trompe ici, un pointeur sur une fonction peut etre un parametre de template, ce qui gère également le cas des méthodes virtuelles

Discussions similaires

  1. Réponses: 6
    Dernier message: 04/06/2010, 11h37
  2. Fonction template, erreur interne du compilateur
    Par Emiler dans le forum Langage
    Réponses: 9
    Dernier message: 08/04/2009, 12h14
  3. [BOOST] erreur interne du compilateur
    Par venomelektro dans le forum Bibliothèques
    Réponses: 1
    Dernier message: 15/04/2006, 18h08
  4. Message d'erreur Internal process...
    Par Systemic7 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 19/07/2005, 13h17
  5. Réponses: 3
    Dernier message: 13/08/2004, 09h35

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