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 :

Portage sous Linux et g++ tatillon


Sujet :

C++

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut Portage sous Linux et g++ tatillon
    Bonjour à tous,

    Je suis en train de porter des bibliothèques sous Linux (g++), que j'avais développé sous Windows (MSVC).

    Un des problèmes récurrent que je rencontre avec g++, est qu'il vérifie le corps d'une fonction template avant son utilisation.

    Par exemple (à la main juste pour expliciter le phénomène) :
    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
     
    // a.h
    class A
    {
    public:
       static void SomeMethod(int i);
    };
     
    // b.h
    template<int I> void ExecSomeMethod()
    {
        A::SomeMethod(I);
    }
     
    // c.h
    ExecSomeMethod<3>();
    Sous Windows, la vérification de la méthode template sera faire lors de son instanciation. Il sera donc possible de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    #include "b.h" // erreur avec g++
    #include "a.h"
    ExecSomeMethod<3>();
    Tandis que g++ lui, lors de la première inclusion "b.h", il va protester comme quoi le symbole "A" n'existe pas..

    Dans mon cas, une bibliothèque essentiellement basée sur la méta programmation, c'est fort problématique.

    Y aurait-il une option à passer à g++ pour ne pas qu'il vérifie le corps des méthodes template avant qu'il ne reçoive les appels avec les paramètres ?

    En vous remerciant par avance,

    A bientôt
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  2. #2
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    C'est étrange je trouve, sous Windows il est également censé dire qu'il ne connait pas la définition de A. Inverse tout simplement les includes a.h et b.h
    Homer J. Simpson


  3. #3
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Apparemment MSVC va vérifier la fonction template que lorsqu'une spécialisation a été appelée, mais pas g++, lui il ne laisse rien passer.

    Pour essayer de simplifier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template<class T> void SomeMethod()
    {
       AClass::Do();
    }
    Lorsque le compilateur va passer dessus, je souhaite qu'il ne vérifie rien jusqu'à tant qu'une spécialisation (dans un .cpp) ne lui soit imposé.

    J'imagine qu'il y a une option dans g++ pour ça, mais laquelle ?

    En tout cas merci pour ta réponse
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Voilà, j'ai reproduit le truc sur un petit fichier :

    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
     
    template<int I>
    class B
    {
    public:
    	static void SomeMethod()
    	{
    		A::SomeMethod();
    	}
    };
     
    class A
    {
    public:
    	static void SomeMethod();
    };
     
    void test()
    {
    	B<3>::SomeMethod();
    }
    Sous Windows ça compile, mais sous linux avec la commande :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    g++ -o test.o -c test.cpp
    J'obtiens une erreur :
    test.cpp: In static member function "static void B<I>::SomeMethod()":
    test.cpp:7:3: error: "A" has not been declared
    Ce qui est fort problématique dans un paradigme tel que la méta programmation, où l'on déclare des comportements plutôt que des entités, que l'on viendra concrétiser via l'appel spécialisation des templates..

    J'ai vraiment besoin d'aide là..
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  5. #5
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Pourquoi veux tu absolument avoir B avant A? Template ou pas, il faut respecter une certaine logique, lorsque tu fais une classe A qui a besoin de B, tu déclare B avant A. Tu utilises une fonction statique, c'est donc la règle de compilation relative au fonction statique qui s'applique et pas à la classe template. Ton template n'a rien à voir dans ton problème ici.
    Homer J. Simpson


  6. #6
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    C'est compliqué à expliquer. Il faut savoir que nous ne sommes pas dans un paradigme traditionnel, mais dans celui de la méta programmation. Actuellement je possède une bibliothèque statique, à niveau abstrait, "méta" que viendra concrétiser une bibliothèque dynamique, qui elle relève de l'ordre concret.

    Comment faire une analogie (c'est toujours plus explicite..)

    Admettons tu exposes une fonction "je vends <des trucs>". MSVC va dire "tu vends, très bien, mais j'attends de savoir ce que tu va vendre pour te donner mon avis". Ma bibliothèque statique est chargée de vendre.

    Ensuite tu définis "je vends<fraise>, je vends<pomme>, je vends<table>", là il va s'intéresser à ta fonction de vendre des fraises, des pommes et des tables, et non des bananes. Peut-être que la vente de fraises ou de pommes ne lui posera pas de problème au compilateur, mais celle des tables, si ! Toujours est-il qui va attendre un peu de concret pour se prononcer.

    Ça se passe à la compilation, et non à l'exécution.

    Tandis que g++ à la définition de "je vends<des trucs>" il va stopper net avec un message "quoi ?". Mais ça n'est pas le moment de savoir quoi, sache qu'il y a une procédure de vente, et tu l'évalueras le moment venu avec ce qu'il est ordonné de vendre..

    C'est un paradigme inhérent au C++, et j'espère bien que g++ le prenne en compte, mais qu'il faille spécifier des options (que je ne connais pas actuellement) afin que la vérification sémantique soit différée à l'instanciation du modèle plutôt qu'à la rencontre d'un code template dont il ne connait pas le contexte de sa concrétisation.

    Bref, l'exemple précédent, simple, démontre mon problème actuel.. Et j'imagine qu'il y a des options dans g++ pour dire "les templates, ne t'en occupes pas de suite, voit ça à la concrétisation"

    C'est précisément ce que je cherche

    En tout cas merci pour cet échange
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    A la rigueur je peux peut-être changer mon organisation même si cela s'avère compliqué pour m'amener à quelque chose que je trouve moins pratique pour l'utilisateur des bibliothèques.

    Mais dans ce cas comment puis-je reporter ces erreurs sous MSVC ? Ce sera ainsi plus facile de travailler sur ce chantier..
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  8. #8
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Comme dans de nombreux cas, il est fort probable que ça soit MSVC qui ne se conforme pas correctement au standard C++, car à la fois gcc et clang voient ce code comme une erreur (je ne saurais pas citer le paragraphe exact de la norme, les mécanismes exacts d'instanciation de templates me passent un peu au dessus de la tête). Je n'utilise pas beaucoup MSVC, donc je ne sais pas s'il est possible de le rentre plus respectueux de la norme avec une option, désolé.

    Toujours est-il que ton organisation me parait effectivement douteuse. Si j'ai bien compris, tes deux fichiers "a.h" et "b.h" font partie de deux bibliothèques différentes, "b" étant une bibliothèque template générique, et "a" une bibliothèque statique d'implémentation. Dans ce cas là, il ne faut pas que "b" fasse référence à une notion qui est définie dans "a" (en l’occurrence ici, ta classe A).

    Tu peux par exemple t'en sortir en transformant A en un paramètre template dans "b.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
    // a.h
    class A
    {
    public:
       static void SomeMethod(int i);
    };
     
    // b.h
    template<typename T, int I> void ExecSomeMethod()
    {
        T::SomeMethod(I);
    }
     
    // c.h
    ExecSomeMethod<A,3>();
    Si tu trouves que c'est lourdingue à écrire, alors il tu peux construire une troisième bibliothèque "ab.h" qui va faire la "glue" entre "b.h" et "a.h", par exemple avec une fonction du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // ab.h
    #include "b.h"
    #include "a.h"
     
    template<int I> void ExecSomeMethod()
    {
        namespace_de_b::ExecSomeMethod<A,I>();
    }
    Ce n'est pas l'idéal question maintenance, mais je doute que tu puisses faire mieux avec ce genre d'organisation. L'idée en général avec les templates c'est de déduire autant que possible les types en fonction des arguments, sans jamais avoir à utiliser un type codé en dur.

    Si tu veux discuter pour changer ton design, il faudrait savoir exactement la fonction de "b.h" et "a.h" dans ton programme.

  9. #9
    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
    C'est effectivement MSVC qui se trompe (et non, il n'est pas possible de corriger son comportement, la fonctionnalité n'est pas encore développée, et difficilement développable). C'est ce qu'on appelle le two-phase lookup.

    Je ne sais pas avec gcc, mais si tu utilises clang, tu as un flag -fdelayed-template-parsing pour la compatibilité avec MSVC qui sans être le même comportement, a un effet proche.

    Sinon, tu peux aussi réécrire ton code pour le rendre conforme. Maintenant, je n'ai pas compris en quoi dans ton exemple ça gênait : A n'est pas un paramètre template de B, c'est pour ça qu'on vérifie ce qui concerne A. S'il en était un, on ne vérifierait rien au premier abord.
    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.

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    En fait, la règle générale est de stricte application dés le moment où ta classe template veut manipuler un type bien particulier, indépendant de ses paramètres template:

    Il faut au minimum que le compilateur connaisse le type si tu te contente de déclarer un pointeur ou une référence sur ce type particulier, et, au maximum, qu'il connaisse l'intégralité du type dés le moment où tu veux déclarer un alias de ce type (typededf) ou si tu veux en appeler une fonction membre.
    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
    /* que la classe A soit template ou non ne change rien à la règle ;) */
    //template <typename T>
    class A;
    /* que la classe soit template ou non ne change rien ici, A étant un type
     * explicite  le compilateur doit au minimum savoir qu'il existe
     * pour accepter qu'on utilise une référence ou  un pointeur.
     */
    // template <typename T>
    class B{
        private:
            A & a_; //légal
    };
     
    /* que la classe soit template ou non ne change rien ici, A étant un type
     * explicite , le compilateur doit connaitre le prototype de A::doSomething() 
     * pour vérifier que l'appel est correct.
     */
    // template <typename T>
    class Bprime{
        public:
            /* le paramètre est légal (le compilateur sait que A existe), l'apel est illégal:
             * le compilateur n'a pas encore croisé le prototype de A::doSomething()
             */ 
            void foo(A /* const & */ a){a.doSomething();}
     
        private:
    };
    L'exception survient lorsque le type utilisé dépend d'un paramètre template (lorsque le type en question est un des paramètres templates à fournir)

    A ce moment là, il faudra en effet attendre l'utilisation explicite pour savoir à quel type réel correspond le paramètre template, simplement parce que le compilateur ne dispose d'aucune information lui permettant de faire la vérification plus tôt.

    Nous pourrons donc déclarer un alias de type sur le paramètre template, simplement parce que, même si l'on ne sait pas exactement ce que ce sera, on sait que le paramètre template existe, et l'on pourra en appeler une fonction membre parce que le compilateur ne devra s'assurer de l'existence de la fonction qu'au moment de l'appel 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
     
    /** Le compilateur sait qu'il existe un type que l'on appelle, pour l'instant T.
       * Mais il ne pourra, de toutes façons, fournir le code correspondant qu'une fois
      * qu'il saura le type réel de T (*)
      *
      */
    template <typename T>
    class C{
        public:
            using alias= T; //C++11 inside, totalement légal
            void foo(){alias::doSomething();} //l'appel de la fonction est légal
    };
    class A{
        public:
            static void doSomething(){/* ... */} 
    };
    void bar(){
    /* arrivé à ce point, le compilateur a déjà rencontré la classe A
     * et peut donc faire toutes les vérifications nécessaires
     *
     */
     C<A> c;// (*) c'est à dire ici. (mais erreur de compilation si A ne dispose
            // pas d'une fonction statique doSomething() )
     c.foo(); 
    }
    Bien sur, je n'ai pas séparé les différentes classes pour l'exemple, mais, si tu les places dans des fichiers séparés, tu pourrais parfaitement utiliser la directive #include qui produirait exactement le même résultat .

    Ce qui importe dans la démonstration, c'est qu'il y a une logique qui doit être suivie: il faut que le compilateur "connaisse" ce qu'on lui demande d'utiliser au moment où on lui demande de l'utiliser.

    Si un compilateur accepte que l'on fasse appel à a.doSomething() dans le premier code sous prétexte que Bprime est une classe template, c'est qu'il est purement et simplement trop permissif, car la classe A est clairement déterminée et ne dépend d'aucune manière d'un des paramètres template de Bprime
    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

Discussions similaires

  1. Portage appels DeviceIoControl windows sous linux
    Par nico2022 dans le forum Linux
    Réponses: 6
    Dernier message: 23/02/2007, 14h18
  2. portage sous linux
    Par rojbi dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 09/11/2006, 13h38
  3. Portage sous linux
    Par rojbi dans le forum Linux
    Réponses: 4
    Dernier message: 19/10/2006, 09h41
  4. Portage d'une application MFC sous Linux/Unix
    Par farscape dans le forum MFC
    Réponses: 29
    Dernier message: 20/02/2006, 17h47
  5. Portage, Librairire de Visual Studio sous Linux ?
    Par HNT dans le forum Visual C++
    Réponses: 9
    Dernier message: 03/02/2006, 23h06

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