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 :

restriction sur une classe template


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 85
    Points : 35
    Points
    35
    Par défaut restriction sur une classe template
    voici le "toy" 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
     
    template< int n=2> 
    struct C{
     
    	int F () {return -n;}
    };
     
     
    template< int n=2> 
    struct A{
     
    	int F () {return n;}
    };
     
    template< int n=2> 
    struct B:public A<n>{
     
    	int F () {return n+1;}
    };
     
    template< class T> 
    struct H{
     
    	int h () { T a; return a.F();}
    };
     
     
    int main()
    {
    	H<A<> > u_a;
    	H<B<> > u_b;
    	H<C<> > u_c;   
     
    	int a = u_a.h();
    	int b = u_b.h();
    	int c = u_c.h();  
     
    	return 0;
    }
    je souhaiterai, si c'est possible, qu ' à la compiliation l'instantiation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    	H<C<> > u_c;   
    	int c = u_c.h();
    envoie une erreur.

    Le but est de restreindre la portée de l 'argument template de H pour seule les classes dérivées de A soient permises et cela sans toucher aux classes A,B ou C.

    Merci encore
    Mathieu

  2. #2
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Je te conseille de regarder du côté de boost.type_traits, en particulier :
    http://www.boost.org/doc/libs/1_40_0...s_base_of.html
    Il te suffit d'utiliser is_base_of<A, ton_paramètre_template>::value dans un endroit qui provoque une erreur de compilation si ça évalue à false. Typiquement : char foo[is_base_of<A, T>::value ? 1 : -1];
    Ou plus simple, un BOOST_STATIC_ASSERT ou similaire.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 85
    Points : 35
    Points
    35
    Par défaut
    Je viens de regarder ta proposition.
    Il n'y a donc pas une synthaxe c++ qui empèche certaines instantiations.
    Il faut avoir recours à Boosts ,que je ne peux pas insérer dans ma librairie de travail

    Au secours!

  4. #4
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Sinon, tu as des petits hacks si tu veux détecter ce genre de choses à la compilation.

    Je verrais bien, par exemple, quelque chose de ce genre (à vérifier, mais l'idée est là) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    struct true_type { char c; }
    struct false_type { };
     
    true_type f(const A& a) { return true_type(); }
     
    template <typename t>
    false_type f(const T& t) { return false_type(); }
     
    // ... dans H< T >
    char foo[sizeof(f(T()) != sizeof(false_type) ? 1 : -1];
    Quelque chose de ce genre en tout cas. Je devrais pouvoir mieux t'éclairer d'ici 2 ou 3 cafés...

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 85
    Points : 35
    Points
    35
    Par défaut
    ok j attends l effet de la caféine alors. Si tu veux aller plus vite, prends du guarana ou emphetamine, c est assez efficace aussi

  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
    Un Kfé bien serré :
    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
    template< int n=2> 
    struct C{
     
    	int F () {return -n;}
    };
     
     
    template< int n=2> 
    struct A{
    	int F () {return n;}
    };
     
    template< int n=2> 
    struct B:public A<n>{
     
    	int F () {return n+1;}
    };
     
     
    struct true_type { char c; };
    struct false_type {true_type t[2]; };// je préfère faire dépendre de true_type pour être sur qu'ils ont vraiment une taille différente
     
    template<int n> true_type f_check(A<n>const&);
    false_type f_check(...);
     
    template<bool ,class> struct enable_if;
    template<class T> struct enable_if<true,T>{typedef T type;};
     
    template< class T> 
    struct H{
       typedef typename enable_if<(sizeof(f_check(T()))== sizeof(true_type)),T>::type check_type;
    	int h () {
          T a; return a.F();
       }
    };
     
    int main()
    {
    	H<A<> > u_a;
    	H<B<> > u_b;
    	H<C<> > u_c;   
       u_a.h();
       u_b.h();
       u_c.h();
     
    	return 0;
    }
    Il existe __is_base_of( base , derived) qui est du Visual spécifique mais que je ne vois pas trop comment appliquer avec une classe de base template sans connaître les paramètres génériques utilisés pour l'héritage.

  7. #7
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    La même que 3Darchi pour moi, le tout bien encapsulé dans une structure, histoire de cacher les détails d'implémentation.
    Y'a juste le coup du T(), si le type n'est pas default-constructible c'est fichu, donc je préfère passer par une fonction helper (juste la signature, on se fiche de la définition ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T makeT(); // pas la peine de la définir puisqu'elle sera juste évalué par sizeof().
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  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
    Citation Envoyé par Goten Voir le message
    Y'a juste le coup du T(), si le type n'est pas default-constructible c'est fichu, donc je préfère passer par une fonction helper (juste la signature, on se fiche de la définition ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T makeT(); // pas la peine de la définir puisqu'elle sera juste évalué par sizeof().
    bien vu

  9. #9
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Un Kfé bien serré
    Volontier

    Citation Envoyé par Goten Voir le message
    La même que 3Darchi pour moi, le tout bien encapsulé dans une structure, histoire de cacher les détails d'implémentation.
    Y'a juste le coup du T(), si le type n'est pas default-constructible c'est fichu, donc je préfère passer par une fonction helper (juste la signature, on se fiche de la définition ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T makeT(); // pas la peine de la définir puisqu'elle sera juste évalué par sizeof().
    Joli, effectivement
    J'en étais arrivé à quelque chose de similaire également.

    Donc pour Mathieu, l'idée, en gros, c'est que tu dois reporter toutes les vérifications & compagnie de l'exécution à la compilation.
    En particulier, ici, ce qui permet de décider, c'est qu'on a 2 fonctions, enfin une fonction qui a 2 surcharges. La première prend un const A&, et donc n'importe laquelle de ses filles. L'autre on s'en fout. La première retourne quelque chose de type true_type, une structure qui n'est pas vide, d'une certaine taille. La seconde false_type, qui a une taille différente de true_type. Tout ça permet le moment venu, de voir la taille de l'objet qui sera retourné par un appel à check, appliqué à n'importe quelle valeur de type T (cf la fonction de Goten). Le mécanisme de résolution des surcharges des compilateurs C++ choisira celle qui prend un const A& si T est A ou une de ses classes filles, sinon il appellera l'autre. Comme les tailles sont différentes, si sizeof(check(makeT())) == sizeof(true_type), alors T hérite de A, ou est A. Sinon, ce n'est pas le cas, et tu peux lancer d'une façon ou d'une autre une erreur de compilation.

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 85
    Points : 35
    Points
    35
    Par défaut
    C est vraiement de la haute voltige.
    Il y a cependant des choses que je ne comprends pas bien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    false_type f_check(...);
    c est un sucharge de la fonction libre f_check qui pour un nombre quelconque d'argument hormis const A<n> & renvoie un false_type a savoir un char[2].


    de même en retirant le mot clef typename de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     typedef typename enable_if<(sizeof(f_check(T()))== sizeof(true_type)),T>::type check_type;
    je provoque une erreur C4346. Si j ai bien compris pour de raison du standard du nouveau compilo, on doit préciser check_type est bien un type?
    Merci Messieurs, vous êtes superbes!

  11. #11
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    C'est quoi la première question? (sur la surcharge)


    Pour typename : Non c'est pour indiquer au compilo que ::type est un type.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  12. #12
    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
    En gros, cela se base sur le SFINAE.
    Aucune de ces fonctions n'est instanciée.
    Elles servent juste à provoquer des erreurs de compilation si cela ne colle pas bien.
    [EDIT] : pour typename : F.A.Q. :A quoi sert le mot-clé typename ?

  13. #13
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par Math75 Voir le message
    C est vraiement de la haute voltige.
    Il y a cependant des choses que je ne comprends pas bien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    false_type f_check(...);
    c est un sucharge de la fonction libre f_check qui pour un nombre quelconque d'argument hormis const A<n> & renvoie un false_type a savoir un char[2].
    Bah, si tu lui passes un const A<n>&, il va prendre la première, pas celle là. Donc c'est cette fonction qui sera choisie si le type passé ne fait pas partie de la hiérarchie de A (A et ses classes filles).

    Mais sinon, oui, c'est une surcharge.


    Citation Envoyé par Math75 Voir le message
    je provoque une erreur C4346. Si j ai bien compris pour de raison du standard du nouveau compilo, on doit préciser check_type est bien un type?
    Merci Messieurs, vous êtes superbes!
    Tu dois préciser que enable_if<(sizeof(f_check(T()))== sizeof(true_type)),T>::type est bien un type. Ca pourrait tout aussi bien être une valeur statique ou enum.

  14. #14
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    @3Darchi : hum, ça se base sur la sélection des fonctions surchargé, mais là je vois pas de SFINAE?
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  15. #15
    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 Goten Voir le message
    @3Darchi : hum, ça se base sur la sélection des fonctions surchargé, mais là je vois pas de SFINAE?
    J'ai parlé trop vite.
    [EDIT] : faut vraiment que j'aille me le chercher ce café.

  16. #16
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Disons que c'est similaire à SFINAE. SFINAE c'est la même chose, sauf que c'est pour détecter l'interface d'une classe : présence d'une fonction foo, d'un membre machin, etc. Mais c'est la même idée puisque comme tu le dis on joue sur la résolution des surcharges (oui, en fait, on manipule ouvertement et sans honte le compilateur).

  17. #17
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Hum, là par contre je te suis pas.

    sauf que c'est pour détecter l'interface d'une classe : présence d'une fonction foo, d'un membre machin
    Ca c'est une application de SFINAE. Après tout SFINAE c'est qu'un mécanisme du compilo on en fait 'ce qu'on veut'.
    Bref toujours est-il que SFINAE s'applique quand t'as des templates, si la substitution du type n'est pas compatible, ça mène pas a une erreur. Là c'est juste de la sélection de fonction par 'affinité'.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  18. #18
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 85
    Points : 35
    Points
    35
    Par défaut
    Merci pour tout.
    Mathieu

  19. #19
    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 Goten Voir le message
    Hum, là par contre je te suis pas.



    Ca c'est une application de SFINAE. Après tout SFINAE c'est qu'un mécanisme du compilo on en fait 'ce qu'on veut'.
    Bref toujours est-il que SFINAE s'applique quand t'as des templates, si la substitution du type n'est pas compatible, ça mène pas a une erreur. Là c'est juste de la sélection de fonction par 'affinité'.
    et le fait que ... est le moins fort dans la sélection.
    Ce que veux dire Alp à mon avis et ce qui m'avait aussi fait parler trop vite, c'est que dans les 2 cas on a un schéma de comportement du compilo similaire : il essaie un truc et si ça marche pas il essaie le suivant sans râler. Mais dans le fond, effectivement, ce n'est pas tout à fait la même chose.

  20. #20
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Ah oui en effet, on peut faire un parallèle, je vois le truc maintenant. Si la première surcharge ne convient pas il passe à la seconde. oki d'oki =)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 12/11/2013, 13h22
  2. Fuite mémoire sur une classe template.
    Par robinsondesbois dans le forum Langage
    Réponses: 17
    Dernier message: 11/07/2013, 16h38
  3. Restriction sur une fonction template
    Par Arzar dans le forum Langage
    Réponses: 12
    Dernier message: 02/10/2009, 00h06
  4. Question sur une classe <template>
    Par Pingva dans le forum C++
    Réponses: 1
    Dernier message: 26/01/2007, 17h16
  5. [MFC] Problème pointeur sur une classe
    Par mick74 dans le forum MFC
    Réponses: 7
    Dernier message: 14/04/2004, 14h17

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