+ Répondre à la discussion
Affichage des résultats 1 à 13 sur 13
  1. #1
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut Instantiation implicite de templates

    Bonjour,

    J'ai une classe template A qui contient un champ de données membre statique x. Y-a-t'il un moyen de s'assurer que A<T>:: x va être réellement instancié (ie. symbole créé dans le fichier objet), pour toute instantiation implicite de A. On garantit qu'un objet de type A<T> est créé.

    Exemple :

    Code :
    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
    // a.hpp
    template<typename T>
    struct A {
      unsigned x;
     
      A();
    };
     
    template<typename T>
    unsigned A<T>::x;
     
    // a.tpp
    #include "a.hpp"
     
    template<typename T>
    inline A<T>::A() {
      // quelque chose ici pour forcer A<T>::x
    }
     
    // a.cpp
    #include "a.hpp"
    #include "a.tpp"
     
    A<int> objet;
     
    // b.cpp
    #include "a.hpp"
     
    // contrat : A<int> instancié quelque part
    int main() {
      std::cout << A<int>::x << std::endl;
      return 0;
    }
    Pour l'instant j'ai tenté le code suivant :

    Code :
    1
    2
    3
    4
    5
    template<typename T>
    inline A<T>::A() {
      unsigned* u = &A::x;
      (void)u; // pas de warning
    }
    Il fonctionne (a.o continent bien A<int>:: x), pour une compilation avec "g++ -O0", mais le symbole disparaît dès que l'optimisation est activée ("g++ -O1" suffit) .

    Avec-vous une quelconque idée ?

    Cordialement,

    Camille

  2. #2
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    Salut,

    Il est vrai que je viens de passer plusieurs heures sur une réponse et que je dois donc tout doucement commencer à fatiguer, mais...

    A moins que je n'ai vraiment pas les yeux en face des trous, il n'y a aucun membre statique dans ta structure

    Erreur de copier / coller, ou oubli réel dans ton code

    Pour déclarer un membre statique dans une structure, il faut utiliser le mot clé static, sous une forme proche de
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<typename T>
    struct A {
      static unsigned x;
     
      A();
    };
     
    template<typename T>
    unsigned A<T>::x = valeurParDefaut;
    Et, à ce moment là, x sera bel et bien créé dans chaque fichier d'implémentation dans lequel tu as une instanciation de A

    Note toutefois que static implique que le membre est "global" dans l'unité de compilation dans laquelle il se trouve.

    Il n'est donc pas forcément impossible que, pou un T donné, tu te retrouves au final avec plusieurs A<T>: répartis dans les différentes unités de compilation dans lesquelles tu aura utilisé A en lui founissant T en paramètre template

    Note aussi que, ne le rendant pas privé dans le cas présent, tu t'expose à ce que "tout et n'importe quoi", y compris les fonctions qui ne disposent pas d'un objet de type A<T>, aille en modifier la valeur à "n'importe quel moment"...

    Ce n'es clairement pas une situation idéale car au final, cela se rapproche très fort d'une variable globale, et tu sais ce qu'on en pense généralement

    Peut etre devrais tu revoir ce point pour t'éviter quelques déboires
    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

  3. #3
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Désolé, pour le static, c'est juste une erreur de copier-coller.
    De même, le "template<...> unsigned A<T>:: x" devrait se trouver dans a.tpp.

    Je connais les risques associés aux globales ; le but réel serait de créer une sorte de constante de classe dépendant de T, calculée dans a.cpp ; puis lue dans un b.cpp, qui n'a accès qu'à la déclaration de la classe A<T>.

  4. #4
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    A ce moment là, tu ferais beaucoup mieux d'encapsuler un tout petit peu A<T>:: x, de manière à ce qu'il ne soit effectivement utilisé que dans a.tpp.

    Si tu le rend constant, cela n'aura pas beaucoup d'importance, mais, à moins qu'il ne s'agisse aussi d'une erreur de copier/coller, A<T>:: x n'est pas constant, et donc, susceptible de changer à beaucoup d'endroit.

    Avec un x constant, tu peux sans problème laisser l'initialisation dans a.hpp et ne pas trop t'en faire pour l'encapsulation, sous une forme proche de
    a.hpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
     
    template<typename T>
    struct A
    {
        static const int x;
    };
    template <typename T>
    int A<T>::x = 153;
    car, à ce moment là, toute unité de compilation qui inclue a.hpp de manière directe ou indirecte disposera de sa propre valeur pour A<NimporteQuoi>:: x, qui sera le même dans toutes les unités de compilations

    Par contre, si A<T>:: x n'est pas constant, il faut veiller à ce que son utilisation ne sorte pas de l'unité de compilation dans laquelle il est effectivement utilisé

    Tu pourrais, par exemple, le faire passer dans l'accessibilité privée et rendre une fonction amie, pour qu'elle puisse en profiter, sous une forme proche de
    a.hpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <typename T>
    class A
    {
        friend void foo(/* ...*/);
        private:
            static int x;
    };
     
    void foo(/*...*/);
    a.tpp
    Code :
    1
    2
    3
    4
     
    template <typename T>
    int A<T>::x = 32;
    /* ...*/
    a.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    #include <a.hpp>
    #include <a.tpp>
    void foo(/* ... */)
    {
       int i = A<Truc>::x;
       /* ... */
    }
    voire, en C++11, profiter de la possibilité d'avoir des template amies
    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

  5. #5
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Merci pour les conseils, mais tu t'attaches à l'encapsulation, qui n'est pas du tout le problème ici.

    La question est en fait : étant donné un type T fixe, quel code faut-il écrire dans a.cpp pour que le symbole A<T>:: x soit accessible depuis b.cpp qui n'inclut pas la définition de A<T>:: x ?

    Après, peu importe qui accède, ou comment, du moment que le symbole est généré.

    Dans le cas général, je sais qu'une instantiation explicite suffit. Mais si je me restreins à une instantiation implicite et un appel de fonction membre ?

    C'est une question théorique sur l'instantiation template en fait.

  6. #6
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    Ce que tu ne sembles pas comprendre, c'est que toute la différence tient dans le fait que x est constant ou non...

    Si c'est "simplement" une constante pure et dure, tu peux sans problème la définir dans ton fichier d'en-tête, car elle sera construite pour chaque implémentation de A<T> que tu pourras faire, dans chaque unité de compilation qui en a besoin, et l'on peut très bien se "foutre éperdument" du fait que cette constante se trouve dans XXX fichiers objet : si elle s'y trouve, c'est que chaque fichier objet utilise une instanciation de A<T> et qu'il en avait donc besoin.

    Par contre, si x n'est pas une constante (et c'est ce que montre ton code, à moins qu'il ne s'agisse d'une erreur de copier coller !!!), alors, il faut savoir que cette variable a une valeur qui est propre à l'unité de compilation qui l'utilise.

    Tu pourrais très bien en arriver à une situation pour le moins dangereuse où Truc.cpp qui instancie A<Truc> se trouve occupé à utiliser A<Truc>:: x avec un valeur de 12, alors que Machin.cpp utilise lui aussi A<Truc> mais dans lequel A<Truc>:: x a une valeur de 126

    C'est une situation pour le moins fragile, tu en conviendras

    C'est la raison pour laquelle j'attire ton attention sur le fait qu'il faut savoir exactement ce que tu attends de A<T>:: x et sur les options qui s'offrent à toi

    C'est d'autant plus vrai que si Truc.cpp instancie A<Truc>, tu cours le risque (selon l'ordre dans d'appel de tes fonctions) qu'une fonction machin qui se trouve dans Machin.cpp essaye d'accéder à A<Truc>:: x alors que la variable n'a pas encore été créée
    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

  7. #7
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Il est parfaitement légal d'écrire :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // a.hpp
    struct A {
      static const int x;
    };
     
    // a.cpp
    #include "a.hpp"
    const int A::x = /* machin */;
     
    // b.cpp
    #include "a.hpp"
    /* on utilise A::x */
    Je demande juste une méthode pour que la même chose fonctionne dans le cas de templates, avec la définition de A<T>:: x uniquement dans a.cpp, et les hypothèses données dans le message d'origine.
    Si tu veux savoir, le calcul de A<>:: x requiert plusieurs centaines de lignes de templates pour obtenir une constante de compilation.

    Ce n'est pas parce que je donne un code rudimentaire sans encapsulation que je ne sais pas l'utiliser, c'est simplement que c'est hors propos de la question.

    Je le répète : c'est une question théorique sur les templates.

  8. #8
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    Citation Envoyé par k1000 Voir le message
    Je demande juste une méthode pour que la même chose fonctionne dans le cas de templates, avec la définition de A<T>:: x uniquement dans a.cpp, et les hypothèses données dans le message d'origine.
    Si tu veux savoir, le calcul de A<>:: x requiert plusieurs centaines de lignes de templates pour obtenir une constante de compilation.
    A ce moment là, tu aurais sans doute intérêt à passer non pas par un static int, mais par une énumération...

    Cela pourrait prendre la forme de
    Code :
    1
    2
    3
    4
    5
    template <typename T, int V>
    struct A
    {
        enum{value = V};
    };
    Si je te conseille cette manière de faire, c'est:
    1. Parce que c'est garanti 0 cost
    2. Parce que cela te permet le cas échéant d'utiliser A::value dans un static_assert
    3. Parce que tu auras tous les avantages d'une variable statique sans en avoir les inconvénients

    Ce n'est pas parce que je donne un code rudimentaire sans encapsulation que je ne sais pas l'utiliser, c'est simplement que c'est hors propos de la question.
    Ce n'est pas la peine de s'énerver non plus : j'ai attiré au moins trois fois ton attention sur le fait que le code que tu fournis semble en contradiction avec ce que tu demandes.

    Tu as corrigé une partie de mes interrogation (en confirmant que x était bien statique), ce n'est que maintenant que tu me confirme qu'il s'agit d'une constante de compilation.

    Avant d'en arriver à ce point de la discussion, il m'était impossible de le savoir (alors que je te l'ai demandé trois fois). J'ai donc veillé à chaque fois travailler selon les deux hypothèses, tout simplement

    Evidemment, il y a toujours une hypothèse qui attire plus l'attention qu'une autre, entre autres, parce qu'elle requière des explications plus longues. Je n'y peux pas grand chose si tu as choisi de te braquer à chaque fois sur ces explications là alors que, comme tu le dis, c'est hors de propos.
    Je le répète : c'est une question théorique sur les templates.
    Je vais donc m'efforcer d'être clair:

    Oui, il est tout à fait valide de définir une variable statique d'une classe template dans un .cpp ou dans un tpp.

    Seulement, si tu le fais, tu n'as qu'une seule garantie quant à l'initialisation de cette variable : en dehors du .cpp dans lequel la valeur est définie ou de tout cpp qui inclut aussi le tpp, tu n'as aucune garantie que la variable aura bel et bien été initialisée.

    C'est à dire que si tu découpes ton code sous une forme proche de
    a.hpp
    Code :
    1
    2
    3
    4
    5
    template <typename T>
    struct A
    {
        static const int x
    };
    a.tpp
    Code :
    1
    2
    template <typename T>
    const int A<T>::x = /* une valeur quelconque */ ;
    truc.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    #include a.hpp
    #include a.tpp
    void foo()
    {
        A<Machin> mavar;
        /* ... */
    }
    bidule.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include <a.hpp>
    // !!! attention !!! pas d'inclusion de a.tpp
    void bar()
    {
        A<Machin> mavar;
        /* ... */
    }
    tu te trouves face au problème que A<Machin>:: x n'est défini que pour l'unité de compilation qui nous permet d'avoir truc.o

    Si tu essayes d'accéder à cette valeur depuis ta fonction bar, tu auras peut etre de la chance... ou pas...

    Avec un peu de chance, selon l'ordre dans lequel l'éditeur de liens aura travaillé, A<Machin>:: x aura été défini, et tu pourra l'utiliser

    Avec un peu moins de chance, ce ne sera pas le cas, et tu te retrouveras avec des résultats aberrants.

    C'est la raison pour laquelle je te conseillerais plutot de passer par une énumération, car tu sera sur que cette constante de compilation est correctement définie
    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

  9. #9
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Citation Envoyé par koala01 Voir le message
    A ce moment là, tu aurais sans doute intérêt à passer non pas par un static int, mais par une énumération...

    Cela pourrait prendre la forme de
    Code :
    1
    2
    3
    4
    5
    template <typename T, int V>
    struct A
    {
        enum{value = V};
    };
    Si je te conseille cette manière de faire, c'est:
    1. Parce que c'est garanti 0 cost
    2. Parce que cela te permet le cas échéant d'utiliser A::value dans un static_assert
    3. Parce que tu auras tous les avantages d'une variable statique sans en avoir les inconvénients
    J'y avais pensé à l'origine, mais l'approche de la variable statique permet de séparer la compilation, économiser du temps compilo, et faire en sorte que b.cpp (code client) n'ait pas à connaître les détails d'implementation.

    Ce n'est pas la peine de s'énerver non plus : j'ai attiré au moins trois fois ton attention sur le fait que le code que tu fournis semble en contradiction avec ce que tu demandes.
    Je te prie de m'excuser si j'ai paru m'irriter. Je tenterai à l'avenir d'être plus clair dès le début.

    Tu as corrigé une partie de mes interrogation (en confirmant que x était bien statique), ce n'est que maintenant que tu me confirme qu'il s'agit d'une constante de compilation.

    Avant d'en arriver à ce point de la discussion, il m'était impossible de le savoir (alors que je te l'ai demandé trois fois). J'ai donc veillé à chaque fois travailler selon les deux hypothèses, tout simplement
    J'ai tenté de donner le moins de données possibles sur la valeur de A:: x pour garder un cas général, et parce qu'elles ne me semblent pas influer.

    Evidemment, il y a toujours une hypothèse qui attire plus l'attention qu'une autre, entre autres, parce qu'elle requière des explications plus longues. Je n'y peux pas grand chose si tu as choisi de te braquer à chaque fois sur ces explications là alors que, comme tu le dis, c'est hors de propos.
    Je vais donc m'efforcer d'être clair:

    Oui, il est tout à fait valide de définir une variable statique d'une classe template dans un .cpp ou dans un tpp.

    Seulement, si tu le fais, tu n'as qu'une seule garantie quant à l'initialisation de cette variable : en dehors du .cpp dans lequel la valeur est définie ou de tout cpp qui inclut aussi le tpp, tu n'as aucune garantie que la variable aura bel et bien été initialisée.

    C'est à dire que si tu découpes ton code sous une forme proche de
    a.hpp
    Code :
    1
    2
    3
    4
    5
    template <typename T>
    struct A
    {
        static const int x
    };
    a.tpp
    Code :
    1
    2
    template <typename T>
    const int A<T>::x = /* une valeur quelconque */ ;
    truc.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    #include a.hpp
    #include a.tpp
    void foo()
    {
        A<Machin> mavar;
        /* ... */
    }
    bidule.cpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include <a.hpp>
    // !!! attention !!! pas d'inclusion de a.tpp
    void bar()
    {
        A<Machin> mavar;
        /* ... */
    }
    tu te trouves face au problème que A<Machin>:: x n'est défini que pour l'unité de compilation qui nous permet d'avoir truc.o

    Si tu essayes d'accéder à cette valeur depuis ta fonction bar, tu auras peut etre de la chance... ou pas...

    Avec un peu de chance, selon l'ordre dans lequel l'éditeur de liens aura travaillé, A<Machin>:: x aura été défini, et tu pourra l'utiliser

    Avec un peu moins de chance, ce ne sera pas le cas, et tu te retrouveras avec des résultats aberrants.

    C'est la raison pour laquelle je te conseillerais plutot de passer par une énumération, car tu sera sur que cette constante de compilation est correctement définie
    Nous voici enfin d'accord sur le thème.
    Maintenant : existe-t-il un moyen pour garantir le cas que tu appelles "chance" ?

    Le standard spécifie que ça fonctionne (ie. la définition de x est instanciée) si x est référencé dans le code de a.cpp. Mon premier post donne une tentative, mais qui se trouve invalidée par l'optimisation. Connais-tu un moyen pour ça ?

  10. #10
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    Citation Envoyé par k1000 Voir le message
    J'y avais pensé à l'origine, mais l'approche de la variable statique permet de séparer la compilation, économiser du temps compilo,
    A part si ta constante est constante quoi qu'il arrive (comprends : contient la même valeur clairement définie quel que soit le paramètre template que tu donneras pour instancier ta classe, comme std::stirng::npos qui est égale à std::numeric_limits<size_t>::max()), cela ne changera strictement rien...

    Et comme tu me dis qu'il faut une centaine de ligne de code template pour arriver à cette valeur, nous nous trouvons clairement dans une situation dans laquelle cela ne changera rien
    et faire en sorte que b.cpp (code client) n'ait pas à connaître les détails d'implementation.
    Tu sais, à moins que tu n'utilises des template de manière totalement privée (comprends : des classes template pour lesquelles tu ne fournis même pas les fichiers d'en-tête parce que toutes les instanciations implicites ou explicites ont été fournies par ailleurs), e client aura de toutes manière les détails d'implémentation.

    Je ne suis personnellement pas persuadé que le fait de pouvoir identifier une valeur numérique changera quoi que ce soit à ce que le client pourra faire avec le code qu'il a en sa possession .

    Maintenant, je te rappelle que je parle de manière tout à fait générale, sans connaitre les tenants et les aboutissants de ton projet
    J'ai tenté de donner le moins de données possibles sur la valeur de A:: x pour garder un cas général, et parce qu'elles ne me semblent pas influer.
    Le problème est que tu tombais dans un cas tellement général que deux hypothèses étaient plausibles, mais bon, ne revenons pas là dessus
    Nous voici enfin d'accord sur le thème.
    Maintenant : existe-t-il un moyen pour garantir le cas que tu appelles "chance" ?
    Ah, ben là...

    J'ai participé il y a quelques semaines à une discussion qui portait à peu près sur ce thême, et qui te donnera peut etre quelques pistes à suivre

    En résumé : il y a peut etre un bug avec g++, ou non, mais le meilleur moyen de t'assurer que tout fonctionne bien est d'être sur que le fichier objet dans lequel ta constante statique est initialisée apparaisse avant tous les fichiers objets dans lequel elle est utilisée lors de l'édition de liens.

    (bon, c'est peut etre pas très clair, alors, si tu ne comprends pas, fait moi signe )

    Le standard spécifie que ça fonctionne (ie. la définition de x est instanciée) si x est référencé dans le code de a.cpp. Mon premier post donne une tentative, mais qui se trouve invalidée par l'optimisation. Connais-tu un moyen pour ça ?
    En ce qui concerne l'optimisation, je ne peux rien dire, mais, en ce qui concerne le fiasco des statiques, un petit tour vers la FAQ ne te donnerait il pas quelques pistes
    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

  11. #11
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Citation Envoyé par koala01 Voir le message
    J'ai participé il y a quelques semaines à une discussion qui portait à peu près sur ce thême, et qui te donnera peut etre quelques pistes à suivre

    En résumé : il y a peut etre un bug avec g++, ou non, mais le meilleur moyen de t'assurer que tout fonctionne bien est d'être sur que le fichier objet dans lequel ta constante statique est initialisée apparaisse avant tous les fichiers objets dans lequel elle est utilisée lors de l'édition de liens.

    (bon, c'est peut etre pas très clair, alors, si tu ne comprends pas, fait moi signe )

    En ce qui concerne l'optimisation, je ne peux rien dire, mais, en ce qui concerne le fiasco des statiques, un petit tour vers la FAQ ne te donnerait il pas quelques pistes
    Le problème ne vient pas de l'initialisation. La définition donne une valeur connue à la compilation, et le standard garantit que l'initialisation statique advient avant toute initialisation dynamique (paragraphe 3.6.2 basic.start.init). Donc tout va bien ici , enfin... si jamais on en arrivait là, tout irait bien .

    Le symptôme se montre plus tôt, au linkage : dans le cas -O0, truc.o contient un symbole A<int>:: x, mais si on optimise -O2, truc.o ne le contient plus et le link échoue.
    Je voudrais juste savoir si il y a un moyen de forcer le symbole A<int>:: x à apparaître dans a.o.

  12. #12
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 766
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 766
    Points : 17 301
    Points
    17 301

    Par défaut

    En fait, je ne sais pas s'il s'agit "simplement" du comportement "normal" d'une des optimisations activées avec -O2 et qu'il suffirait de désactiver (pour tout fKKC, il y a un -f-no-KKC ) ou s'il s'agit plus d'un bug de celle-ci qui en ferait "plus que ce qu'on lui demande"

    Ceci dit, la seule solution pour être sur que cette valeur sera correctement initialisée est et restera l'encapsulation...

    Tu pourrais par exemple, remplacer ta variable membre statique x par une fonction statique, sous la forme de
    Code :
    1
    2
    3
    4
    5
    6
    template <typename T>
    static const int A<T>::x()
    {
        static const int tmp = 153; /* ou toute valeur calculée de ton choix ;)) */
        return tmp;
    }
    et tu aurais donc la certitude que, quoi qu'il arrive, la variable serai initialisée au moment du premier appel à cette fonction

    (note que tu peux même envisager de la déclarer constexpr en C++11 )

    Ceci dit, comme je me plais à le rappeler, on peut aussi penser à une phrase sympa de
    Citation Envoyé par David Wheeler
    all problems in computer science can be solved by another level of indirection .
    et envisager quelque chose comme
    a.hpp
    Code :
    1
    2
    3
    4
    5
    template <typename T>
    struct A
    {
        static const int x;
    };
    a.tpp
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* pas besoin de déclarer ce foncteur dans le fichier d'en-tete, il n'est là que 
     * pour assurer l'initialisation ;) 
     */
    struct JustToBeSure
    {
        int operator () () const 
        {
            static const int temp= 1685;
            return temp;
        }
    };
    template <typename T>
    const int A<T>::x= justToBeSure()();
    Sauf erreur, et bien que je n'aie meme pas essayé de compiler, cela devrait marcher parce que tu serais sur que l'on passe bel et bien dans la fonction qui initialise une valeur statique, et que ta variable prend cette valeur
    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

  13. #13
    Membre du Club
    Homme Profil pro Camille Gillot
    Étudiant
    Inscrit en
    septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Nom : Homme Camille Gillot
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2007
    Messages : 60
    Points : 53
    Points
    53

    Par défaut

    Que ce soit une fonction ou variable statique, le problème est le même si l'instantiation n'advient pas.

    L'initialisation statique est un fait acquis déjà, pas la peine de t'en préoccuper.

    J'ai fini par trouver une réponse tout seul : le mot-clé volatile s'appelle dieu quand l'optimiseur est trop zélé.

    Code final :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // a.hpp
    template<typename T>
    struct A {
      static unsigned const x;
      A();
    };
     
    // a.cpp
    #include a.hpp
    template<typename T>
    unsigned const A<T>x = sizeof(T);
     
    template<typename T>
    A<T>::A() {
      *static_cast<unsigned const volatile*>(&A::x);
    }
     
    A<int> machin;
     
    // b.cpp
    #include a.hpp
    /* utilisation de A<int>::x */
    Cet exemple compile, linke et tourne parfaitement, vu que volatile interdit l'optimisation de la référence à A<>:: x.

    Merci quand-même pour les conseils généraux.

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •