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 :

Amitié template spécialisée


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut Amitié template spécialisée
    Bonjour, j'aimerais faire une amitié d'un template avec un template spécialisé, est-ce possible ? Si oui, quelle est la syntaxe...

    Pour exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<class A, class B>template_ami;
     
    template<class T>un_template
    {
      template<class U>friend class template_ami<T,U>;
    };
    Et GCC me refuse :
    erreur: partial specialization ‘template_ami<T, U>’ declared ‘friend’

    Parce qu'il est possible de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<class A, class B>template_ami;
     
    template<class T>un_template
    {
      template<class U, class V>friend class template_ami;
    };
    Mais ça n'a aucun intérêt puisque tous les template_ami peuvent être ami avec tous les un_template de n'importe quel type, l'intérêt étant de spécialiser l'amitié en fonction des types des deux templates...

  2. #2
    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 GMany Voir le message
    Mais ça n'a aucun intérêt puisque tous les template_ami peuvent être ami avec tous les un_template de n'importe quel type, l'intérêt étant de spécialiser l'amitié en fonction des types des deux templates...
    A mon avis la réponse est dans une question : montres un exemple qui compile de transgression que tu voudrais interdire (et où tu ne serais pas passé par une spécialisation au - partielle).

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Un exemple qui compile je ne pense pas pouvoir vous le faire, parce que je développe avec mes propres librairies, qui ne sont pas en libre de droits.

    Mais je peux faire un exemple avec une syntaxe générique type pseudo-code :

    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
    template<class Obj, class Key>class manager
    {
     
      private :
     
        List<Object<Obj> *,Key>;
     
    };
     
    template<class Obj>class Object
    {
     
      template<class A, class B>friend class manager;
     
      private :
     
        Obj *;
     
    };
    (J'ai écris List je suppose que quelqu'un qui utilise STL écrira map)

    Bien sûr les classes là sont très simples, on peut se demander l'utilité de la classe Object. Mais il suffit de rajouter plein de membres privés à Object en faire une classe utile.

    L'essentiel c'est de voir que par exemple, manager<voiture,int> est aussi ami avec Object<batiment>, alors que voiture et batiment sont deux classes clairement différentes.

    Ce qu'on voudrait, c'est que seules les classes manager<voiture,T> soient amies avec la classe Object<voiture>.

  4. #4
    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,
    Ce que je voulais dire, c'est que soit tu manipules en permanence du générique et alors template<class U, class V>friend class template_ami; suffit. Soit tu es amené à faire une spécialisation partielle et alors c'est dans cette spécialisation partielle qu'il te faut positionner ton amitié.
    C'est pourquoi je te demandais un exemple (pas forcément de ton code) où tu ne spécialises pas partiellement (ou totalement) et où l'amitié te permet de transgresser une encapsulation que tu ne souhaiterais pas. J'avoue que je crois que c'est tout bonnement pas possible. D'où je pense que la question ne se pose pas en fait.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Pour faire une transgression c'est plutôt simple, il suffit de considérer deux instances d'une même classe mais pas du même type...

    Je reprend mon exemple précédent, que je complète un peu...

    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
    template<class Obj, class Key>class manager
    {
    
      private :
    
        List<Object<Obj> *,Key> list;
        Object<Obj> *GetKey(Key);
    
        template<class X, class Y>void methode(manager<X,Y> *, Y);
    
    };
    
    template<class Obj, class Key>template<class X, class Y>void manger<Obj,Key>::methode(manager<X,Y> *x, Y y)
    {
       Object<X> *obj=x->GetKey(y);
       // [0] Je peux faire ce que je veux avec obj
    }
    
    template<class Obj>class Object
    {
    
      template<class A, class B>friend class manager;
    
      private :
    
        Obj *p;
    
    };
    On voit très bien au commentaire [0] que le manager de type <voiture,int> peut accéder à tous les champs sans souci de Object<batiment> via la méthode manager::methode<batiment,int> par exemple...

    Bien sûr, ce n'est qu'un exemple, mais l'intérêt d'une amitié template spécialisée est de restreindre l'accès de la classe à un template en fonction de son type. Et je suppose que ce n'est pas le seul exemple qu'on pourrait rencontrer...

    Par ailleurs, c'est ce qui est fait implicitement, quand la spécialisation est totale. Par exemple, deux templates de même type, et une amitié :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<class T>class A{};
     
    template<class T>class B
    {
      friend class A<T>;
    };
    Ici il n'est pas question que A<char> soit ami avec B<int>, par contre, A<int> et B<int> sont amis. Du coup, on fait exactement une amitié en fonction du type.
    Et donc il devrait être logique qu'il soit possible de restreindre en fait l'amitié de B<T> à tous les templates de type A<T'=T,U,V,...>.

  6. #6
    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,
    J'ai trouvé ça dans la norme :
    Friend declarations shall not declare partial specializations. [Example:
    template<class T> class A { };
    class X {
    template<class T> friend class A<T*>; // error
    };
    —end example]
    Et j'aurais tendance à dire que ce que tu veux faire est une amitié en déclarant une spécialisation partielle.
    La réponse serait donc non c'est pas possible tel quel...

  7. #7
    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
    (Re)Salut,
    En reprenant ton exemple :
    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
    #include <map>
    template<class Obj>class Object;
     
    template<class Obj, class Key>
    class manager
    {
     
      private :
     
        std::map<Key,Object<Obj> *> mon_map;
        Object<Obj> *GetKey(Key k_){
           return mon_map[k_];
        }
     
    public:
        template<class X, class Y>void methode(manager<X,Y> *x, Y y)
        {
          Object<X> *obj=x->GetKey(y);
          obj->p->do_it();
        }
     
    };
     
    template<class Obj>class Object
    {
     
      template<class X, class Y>friend class manager;
     
      private :
     
        Obj *p;
     
    };
    class A
    {
       public:
       void do_it(){}
    };
     
    class B
    {
       public:
       void do_it(){}
    };
     
    int main()
    {
       manager<A,int> m1;
       manager<B,char> m2;
       m1.methode(&m2,'c');
       m1.methode(&m1,1);
       return 0;
    }
    si Object<Obj> *GetKey(Key k_) est private dans manager, alors m1.methode(&m2,'c') provoque une erreur : logique manager<A,int> et manager<B,char> sont 2 classes différentes donc la première ne peut accéder aux membres privés de la seconde.

    Sinon, je ne vois que 2 solutions (assez peu satisfaisantes il est vrai) :
    -> La première consiste à déclarer un manager pour chaque type et ne donner l'amitié qu'à celui-là :
    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
    #include <map>
    template<class Obj>class Object;
     
    template<class Obj, class Key>
    class manager
    {
     
      private :
     
        std::map<Key,Object<Obj> *> mon_map;
    protected:
        Object<Obj> *GetKey(Key k_){
           return mon_map[k_];
        }
     
    public:
        template<class X, class Y>void methode(manager<X,Y> *x, Y y)
        {
          Object<X> *obj=x->GetKey(y);
          obj->p->do_it();
        }
     
    };
     
    template<class Key> class manager_de_A;
     
    template<class Obj>class Object
    {
     
    public:
       template<class B>friend class manager_de_A;
     
      private :
     
        Obj *p;
     
    };
     
    class A
    {
       public:
          void do_it(){}
    };
     
    class B
    {
       public:
       void do_it(){}
    };
     
    template<class Key> class manager_de_A : public manager<A,Key>
    {
    public:
       void methode(manager_de_A *x, Key y)
       {
       Object<A> *obj=x->GetKey(y);
       obj->p->do_it();
       }
    };
     
     
    int main()
    {
       manager_de_A<int> m1;
       manager<B,char> m2;
       //m1.methode(&m2,'c'); provoque une erreur
       m1.methode(&m1,1);
       return 0;
    }
    La deuxième s'inspire un peu de la première si ce n'est que manager_de_A est membre de Object :
    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
    #include <map>
    template<class Obj>class Object;
     
    template<class Obj, class Key>
    class manager
    {
     
      private :
     
        std::map<Key,Object<Obj> *> mon_map;
    protected:
        Object<Obj> *GetKey(Key k_){
           return mon_map[k_];
        }
     
    public:
        template<class X, class Y>void methode(manager<X,Y> *x, Y y)
        {
          Object<X> *obj=x->GetKey(y);
          obj->p->do_it();
        }
     
    };
     
    template<class Obj>class Object
    {
     
    public:
       template<class Key>
       class manager_de_obj : public manager<Obj,Key>
       {
       public:
           void methode(manager_de_obj *x, Key y)
           {
             Object<Obj> *obj=x->GetKey(y);
             obj->p->do_it();
           }
       };
     
       template<class B>friend class manager_de_obj;
     
      private :
     
        Obj *p;
     
    };
     
    class A
    {
       public:
          void do_it(){}
    };
     
    class B
    {
       public:
       void do_it(){}
    };
     
    int main()
    {
       Object<A>::manager_de_obj<int> m1;
       Object<B>::manager_de_obj<char> m2;
    //   m1.methode(&m2,'c'); provoque une erreur
       m1.methode(&m1,1);
       return 0;
    }

  8. #8
    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
    Éventuellement, il y a une troisième solution en rajoutant à Object un paramètre template indiquant son manager et en ne donnant l'amitié qu'à celui-là. Cependant, l'amitié ne peut à priori pas se transmettre à un paramètre template. Mais il semblerait qu'on puisse tricher ... mais d'une façon qui dépend du compilateur :
    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
    #include <map>
    template<class Obj,class TManager>class Object;
    
    template<class Obj, class Key>
    class manager
    {
    
      private :
    
        std::map<Key,Object<Obj,manager<Obj,Key> > *> mon_map;
    protected:
        Object<Obj,manager<Obj,Key> > *GetKey(Key k_){
           return mon_map[k_];
        }
    
    public:
        template<class X, class Y>void methode(manager<X,Y> *x, Y y)
        {
          Object<Obj,manager<Obj,Key> > *obj=x->GetKey(y);
          obj->p->do_it();
        }
    
    };
    template <class T>
    struct Identite
    {
       typedef T Type;
    };
    
    template<class Obj, class TManager>
    class Object
    {
    
    public:
    // pour gcc (MingGW :)
       friend class Identite<TManager>::Type;
    // pour Visual (VCExpress) :
       friend typename Identite<TManager>::Type;
    
      private :
    
        Obj *p;
    
    };
    
    class A
    {
       public:
          void do_it(){}
    };
    
    class B
    {
       public:
       void do_it(){}
    };
    
    int main()
    {
       manager<A,int> m1;
       manager<B,char> m2;
       //m1.methode(&m2,'c'); provoque une erreur
       m1.methode(&m1,1);
       return 0;
    }

Discussions similaires

  1. Réponses: 3
    Dernier message: 09/04/2009, 11h30
  2. [Template] Spécialisation partielle d'un template
    Par Kurisu dans le forum Langage
    Réponses: 31
    Dernier message: 25/11/2008, 22h21
  3. [Template] spécialisation partielle des template
    Par vikki dans le forum Langage
    Réponses: 9
    Dernier message: 10/11/2008, 16h29
  4. Template, spécialisations et définitions multiples.
    Par 3DArchi dans le forum Langage
    Réponses: 3
    Dernier message: 26/09/2008, 17h45
  5. Réponses: 19
    Dernier message: 18/03/2007, 16h57

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