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

Langage C++ Discussion :

référence vers un membre de structure comme paramètre d'un template


Sujet :

Langage C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2018
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2018
    Messages : 3
    Par défaut référence vers un membre de structure comme paramètre d'un template
    Bonjour,
    Je voudrais utiliser une référence vers un membre d'une structure comme paramètre d'un template. Mais le compilateur (GCC) refuse parce que "it is not an object with linkage".

    Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    template <int& var> class X
    {
    };
     
    int a;
    typedef X<a> X1; // working
     
    struct
    {
      int b;
    } s;
    typedef X<s.b> X2; // not working
    Quelqu'un a-t-il une idée qui me permettrait de résoudre mon problème ?
    Merci !

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Salut,

    Cela me semble très curieux ce que tu veux faire...

    As-tu bien compris que les template sont résolus à la compilation, et que, si on peut utiliser des valeurs numériques dans certaines circonstances, on ne peut donc le faire qu'à condition que ce soient des constante de compilation

    Par exemple, nous pouvons utiliser le retour de la fonction sizeof() qui correspond à la taille (connue par le compilateur ) du type indiqué entre parenthèse, ou les valeurs énumérées d'une énumération:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    enum MyValue{
        zero, // == 0
        one, // == 1
        two, // == 2
        three, // == 3
    };
     
    template <int T>
    struct Test{
         static constexpr value=T;
    }
    int main(){
        std::cout<<Test<three>::value<<"\n";
    }
    parce que la valeur numérique associée à chaque valeur énumérée est forcément connue du compilateur, vu qu'il doit la calculer pour pouvoir l'utiliser.

    Mais le compilateur ne pourra générer le code binaire qui correspond à une valeur numérique que... s'il connait cette valeur au moment de la compilation.

    Une solution pourrait être de:
    • nommer ta structure (obligatoire pour permettre l'étape suivante)
    • déclarer le membre de ta structure comme un membre statique et constant (static const int ), ou mieux, comme une valeur constexpr statique (static constexpr int b) (*)
    • Pour éviter les problème de CV-qualifier: soit déclarer ton paramètre var comme int const & var, soit veiller à supprimer les cv-qualifier

    (*) static pour que le membre ne dépende pas d'une instance de la classe, constant ou constexpr pour que le compilateur sache que cette valeur ne changera pas
    Mais la question se pose alors (et elle se pose déjà du simple fait que tu exposes ton problème) : pourquoi voudrais tu utiliser une référence comme paramètre template

    Car, soyons bien clairs :
    Il n'y a aucun intérêt à transmettre un type primitif par référence à une fonction, à moins, bien sur, que la fonction appelée ne doive modifier durablement la valeur du paramètre qui lui est transmis (et que cette modification doit s'appliquer au niveau de la fonction appelante).
    Or, comme je te l'ai rappelé la tout de suite, les paramètres template sont résolus à la compilation, ce qui empêche forcément n'importe quelle fonction d'apporter la moindre modification de valeur...

    Enfin, si la première partie de ton code fonctionne, c'est essentiellement parce qu'elle ne veut absolument rien dire pour le compilateur, dans le sens où il n'a aucun code binaire exécutable à générer à partir de ce code. Mais, essaye de l'utiliser (autrement qu'en demandant la taille de X1), et tu verras les erreurs tomber de partout
    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
    Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2018
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2018
    Messages : 3
    Par défaut
    Salut koala01,

    Merci pour ta réponse.

    J'avais simplifié le code à l'extrême pour expliquer le problème.

    L'objectif de ma classe template est de créer un accesseur vers un membre statique d'une classe.

    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
     
    template <int & var>
      class Accessor
    {
      public:
     
        /* Accès direct */
     
        static int get(void)
        {
          return(var);
        }
     
        static void set(const int newValue)
        {
          var = newValue;
        }
     
        /* Accès après conversion */
     
        static float getAsFloat(void)
        {
          return(float(var));
        }
     
        static void set(const float newValue)
        {
          var = int(newValue);
        }
    };
    Dans mon cas, je considère que la référence vers une variable est une sorte de pointeur. Comme la variable est statique, l'adresse de cette variable est connue lors de la compilation. Si je n'utilise pas de pointeur, c'est pour garantir au compilateur que la variable référencée existe et éviter les problèmes tels que la comparaison avec NULL.


    On peut utiliser cette classe de la manière suivante :

    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
     
    typedef struct
    {
      int d;
      int e;
    } MyStruct;
     
    class MyClass
    {
      private:
        static int a;
        static int b;
        static int c;
     
        static MyStruct s;
     
      public:
        typedef Accessor<a> AccessToA;
        typedef Accessor<b> AccessToB;
        typedef Accessor<c> AccessToC;
        typedef Accessor<s.d> AccessToD; // ne compile pas
    };
     
     
    int MyClass::a = 0;
    int MyClass::b = 0;
    int MyClass::c = 0;
    MyStruct MyClass::s = {0, 0};
     
     
    void main(void)
    {
      MyClass::AccessToA::set(float(1.0));
    }
    Il me semble que le compilateur connaît l'adresse de s.d au même titre que celle de a et que ça pourrait donc fonctionner...

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Ohhh... Mais pourquoi veux tu un accesseur et, pire encore, un mutateur

    Ne t'a-t-on jamais appris que tu dois considérer tes classes comme des fournisseurs de services

    Si tu en viens à fournir un accesseur et un mutateur à une donnée membre, pourquoi ne pas -- directement -- la placer dans l'accessibilité publique, cela te simplifiera la vie!!!!

    Un accesseur, cela peut éventuellement se comprendre, car on peut considérer le fait que répondre à la question "quelle est la valeur XXX?" comme un service que l'on est en droit d'attendre de la part de la classe.

    Mais, pour tout ce qui a trait à la modification de valeur, si tu rend l'utilisateur de ta classe responsable des calculs qui permettent de définir la nouvelle valeur tu n'as aucun intérêt à encapsuler ta donnée, car tu dois t'attendre à ce que l'utilisateur fasse "du grand n'importe quoi" lors de son calcul.

    Or, ta donnée, elle subit toute une série d'obligations et de restrictions qui doivent impérativement être respectées, si tu veux que ton programme fonctionne de manière cohérente. C'est donc au développeur de la classe de faire en sorte:
    1. d'effectuer lui-même les calculs en prenant toutes les obligations et les restrictions en compte
    2. de fournir une fonction permettant à l'utilisateur d'introduire les paramètres qui seront utilisés pour le calcul.

    (par exemple, en fournissant une fonction move(diffX, diffY) au lieu d'une fonction setPosition(x, y).

    En plus, les données statiques non constantes, c'est la foire à l'embrouille garantie
    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
    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
    Par défaut
    Au delà des (bonnes) remarques de Koala, je peux te montrer les éléments de la norme qui montrent que le code en question n'est pas valide (et donc que ton compilateur a raison de le refuser), mais j'imagine que tu cherches à comprendre pourquoi, mais ça, ce n'est pas dans la norme, et je n'ai pas d'idées a priori sur ce sujet.

    Je suis d'accord avec toi que l'adresse pourrait être connue à la compilation, et qu'on pourrait donc imaginer que ce genre de code puisse marcher (mais ce n'est pas la formulation retenue par la norme, qui perle juste de linkage, pas d'adresses constantes connues à la compilation). Peut-être que la différence est que l'adresse pourrait être déduite, alors que pour les objets qui ont un linkage, et est déjà directement disponible, ce qui simplifie les choses ? J'imagine aussi que si c'était autorisé, on pourrait avoir des problèmes pour savoir si deux instances de template sont identiques :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    union A
    {
         int i;
         int j;
    };
     
    struct B
    {
        static A a;
    };
     
    using u1 = Accessor<B::A::i>;
    using u2 = Accessor<B::A::j>;
    u1 et u2 sont-ils deux instances différentes ou pas ?
    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.

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/01/2010, 19h32
  2. c++ vers c# tableau comme paramétres de fonction
    Par punto dans le forum Windows Forms
    Réponses: 3
    Dernier message: 21/03/2008, 11h21
  3. Réponses: 2
    Dernier message: 24/08/2007, 01h54
  4. Réponses: 6
    Dernier message: 12/02/2006, 18h02
  5. Un fichier .bmp comme paramètre d'une Procédure stockée
    Par FONKOU dans le forum Bases de données
    Réponses: 2
    Dernier message: 28/10/2004, 17h56

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