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 :

Relation d'ordre entre paramètres template.


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut Relation d'ordre entre paramètres template.
    Bonjour.

    J'ai créé une classe template avec deux paramètres T1 et T2 et j'aurais aimé garantir que sizeof(T2)>sizeof(T1). Malheureusement, je ne vois pas comment faire.

    En effet, j'ai tout d'abord essayé d'autiliser une sous class prenant un unsigned, mais je n'ai pas l'erreur à la compilation..
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T1, class T2>
    class A
    {
       private:
       template<unsigned int T>
       class B
       {
       };
       B<sizeof(T2)-sizeof(T1)> ex;
    };
    Je me trouve donc un peu bloqué... si quelqu'un avait une idée...

    merci
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  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
    Salut,
    Boost::enable_if:
    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
     
    #include <boost/utility/enable_if.hpp>
     
    template <class T1, class T2, class dummyT=typename boost::enable_if_c<(sizeof(T1)>sizeof(T2))>::type>
    struct A
    {
    };
     
    struct B1
    {
       unsigned char uc;
    };
    struct B2
    {
       unsigned char uc[2];
    };
     
    int main()
    {
       A<B2,B1> a1;
    //   A<B1,B2> a1; --> Error
       return 0;
    }
    Ou :
    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
    template<bool> struct enable_if_c;
    template<> struct enable_if_c<true>
    {
       typedef void type;
    };
     
    template <class T1, class T2, class dummyT=typename enable_if_c<(sizeof(T1)>sizeof(T2))>::type>
    struct A
    {
    };
     
    struct B1
    {
       unsigned char uc;
    };
    struct B2
    {
       unsigned char uc[2];
    };
     
    int main()
    {
       A<B2,B1> a1;
    //   A<B1,B2> a1;
       return 0;
    }
    Cependant, j'aurais tendance à dire que comparer la taille de 2 types n'est pertinent que dans un cadre de méta-prog si les 2 types sont liés entre eux (typiquement pour du sfinae).

  3. #3
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Cependant, j'aurais tendance à dire que comparer la taille de 2 types n'est pertinent que dans un cadre de méta-prog si les 2 types sont liés entre eux (typiquement pour du sfinae).
    Je dois reconnaitre que je n'utilise que des types numériques et leurs dérivés munis des opérations +, -, *, = et ==. le véritable test "mathématique" devrais porter sur l'inclusion de l'ensemble T1 dans l'ensemble T2, mais je me suis dit qu'une simple comparaisons de types serait sufisante... a moins qu tu voie autre chose....


    Sinon, vis à vis de ton exemple, il serait peut-être plus pertinent d'instancier A dans une classe contenante histoire d'éviter que l'utilisateur puisse spécifier le paramètre dummyT non ?

    merci
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  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
    Citation Envoyé par méphistopheles Voir le message
    Sinon, vis à vis de ton exemple, il serait peut-être plus pertinent d'instancier A dans une classe contenante histoire d'éviter que l'utilisateur puisse spécifier le paramètre dummyT non ?
    Effectivement. Instancier pose le problème d'ajouter un membre qui ne sert à rien. Vaut mieux utiliser un héritage privé (qui ne sert à rien) mais que le compilo optimise pour n'utiliser pas plus d'espace :
    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
     
    namespace details{ 
       struct dummy{};
    }
    template<bool,typename T> struct enable_if_c;
    template<typename T> struct enable_if_c<true,T>
    {
       typedef T type;
    };
     
    template <class T1, class T2>
    struct A : private enable_if_c<(sizeof(T1)>sizeof(T2)),details::dummy>::type
    {
    };
     
    struct B1
    {
       unsigned char uc;
    };
    struct B2
    {
       unsigned char uc[2];
    };
     
    int main()
    {
       A<B2,B1> a1;
       //A<B1,B2> a2; //--> Error
       return 0;
    }
    Citation Envoyé par méphistopheles Voir le message
    Je dois reconnaitre que je n'utilise que des types numériques et leurs dérivés munis des opérations +, -, *, = et ==. le véritable test "mathématique" devrais porter sur l'inclusion de l'ensemble T1 dans l'ensemble T2, mais je me suis dit qu'une simple comparaisons de types serait sufisante... a moins qu tu voie autre chose....
    En jouant avec std::limits : à l'exécution avec std::numeric_limits<>::min ou à la compilation avec l'enable_if et std::numeric_limits<>::digits10. Mais ça reste un peu de la bidouille.
    Mais ton problème ne peut-il se résoudre avec les Boost.numeric cast ?

  5. #5
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<bool,typename T> struct enable_if_c;
    template<typename T> struct enable_if_c<true,T>
    {
       typedef T type;
    };
    Heu... à quoi sert le type T ? il n'est pas essentiel si ? (à moins qu'on ne puisse hériter de void)...

    Citation Envoyé par 3DArchi Voir le message
    En jouant avec std::limits : à l'exécution avec std::numeric_limits<>::min ou à la compilation avec l'enable_if et std::numeric_limits<>::digits10. Mais ça reste un peu de la bidouille.
    Mais ton problème ne peut-il se résoudre avec les Boost.numeric cast ?
    A vrai dire, ce sont de types numériques mais certains étant définis par l'utilisateur , je ne suis pas sûr qu'ils soient standards donc boost risque de tomber sur un os...


    Je vais par contre rester sur la première solution.


    Merci beaucoup
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  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
    Citation Envoyé par méphistopheles Voir le message
    Heu... à quoi sert le type T ? il n'est pas essentiel si ? (à moins qu'on ne puisse hériter de void)...
    Effectivement, on ne peut hériter de void (ni de int, ni de char, etc.)

  7. #7
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Heu... à quoi sert le type T ? il n'est pas essentiel si ? (à moins qu'on ne puisse hériter de void)...
    J'était justement entrain de me demander pourquoi utiliser enable_if(qui nous embête avec ce type T) et pas BOOST_STATIC_ASSERT?

    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
    template <class T1, class T2>
    struct A
    {
      BOOST_STATIC_ASSERT(sizeof(T1)>sizeof(T2));
    };
     
    //Ou éventuellement, pour profiter de l'héritage privé:
    template<bool>
    struct StaticAssert;
    template<>
    struct StaticAssert<true>{};
    template <class T1, class T2>
    struct A : StaticAssert<sizeof(T1)>sizeof(T2)>
    {
    };

  8. #8
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    J'ai finalement utilisé la méthode de nogame qui marche parfaitement.


    Merci encore à tous
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  9. #9
    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
    Effectivement, c'est le plus simple. J'ai pas eu le réflexe du static assert mais c'est dans ce cas peut être plus aisé à mettre en œuvre.

  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

    Le fait est que BOOST_STATIC_ASSERT fait exactement la même chose ce ce que ce que 3D fait avec son enable_if_c...:

    on a, en effet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <bool x> struct STATIC_ASSERTION_FAILURE;
     
    template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
     
    // HP aCC cannot deal with missing names for template value parameters
    template<int x> struct static_assert_test{};
    comme structure ayant certaines spécialisation et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #define BOOST_STATIC_ASSERT( B ) \
       enum { BOOST_JOIN(boost_static_assert_enum_, __LINE__) \
          = sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >) }
    pour les tests à coup de BOOST_STATIC_ASSERT
    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 confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Note: Tu peux également utiliser static_assert de C++0x

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static_assert( sizeof( T1 ) < sizeof( T2 ), "sizeof( T1 ) doit être plus petit que sizeof(T2) !" );

  12. #12
    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
    Citation Envoyé par JulienDuSud Voir le message
    Note: Tu peux également utiliser static_assert de C++0x

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static_assert( sizeof( T1 ) < sizeof( T2 ), "sizeof( T1 ) doit être plus petit que sizeof(T2) !" );
    Oui, mais bon...
    1. C++0x n'est pas encore officiellement accepté, et les compilateurs ne le respectent pas par défaut
    2. Son static_assert (celui de C++0x) est, très certainement, basé sur celui de boost (ou un quelconque similaire)
    3. Cela revient, de toutes manières, strictement au même que les deux possibilités envisagées jusqu'à présent, avec une restriction supplémentaire (quid si ton programme doit être compilé avec un compilo plus ancien )
    Dans trois ans, quand la norme aura été finalisée et que les compilateurs actuels la suivront par défaut, je ne dis pas...

    Mais, à l'heure d'écrire ces lignes, je ne suis pas absolument certain que le fait d'utiliser C++0x en production soit réellement une bonne idé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

  13. #13
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Oui, mais bon...
    1. C++0x n'est pas encore officiellement accepté, et les compilateurs ne le respectent pas par défaut
    2. Son static_assert (celui de C++0x) est, très certainement, basé sur celui de boost (ou un quelconque similaire)
    3. Cela revient, de toutes manières, strictement au même que les deux possibilités envisagées jusqu'à présent, avec une restriction supplémentaire (quid si ton programme doit être compilé avec un compilo plus ancien )
    Dans trois ans, quand la norme aura été finalisée et que les compilateurs actuels la suivront par défaut, je ne dis pas...

    Mais, à l'heure d'écrire ces lignes, je ne suis pas absolument certain que le fait d'utiliser C++0x en production soit réellement une bonne idée
    Certes, mais il a quelques choses qu'il ne faut pas négliger:

    Pas besoin de boost pour l'utiliser, il fait partie du standard.
    Permet de mettre en place un message d'erreur compréhensible.

    C'était juste une note; qui plus est, static_assert c'est uniquement du compile-time et donc sans danger pour tout code qui passe cette étape, donc sans danger pour les soft en production.

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

Discussions similaires

  1. Requête avec relation N-N (entre 3 tables)
    Par vynce dans le forum Langage SQL
    Réponses: 11
    Dernier message: 05/12/2005, 10h34
  2. relation maitre/esclave entre 2 BDD sur MySQL?
    Par root76 dans le forum SQL Procédural
    Réponses: 5
    Dernier message: 14/10/2005, 14h37
  3. Relation de dépendance entre résultats : une idée farfelue ?
    Par mdef dans le forum Langages de programmation
    Réponses: 4
    Dernier message: 18/07/2005, 02h04
  4. Mettre une relation 1,1 entre 2 tables
    Par borgfabr dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 11/05/2005, 17h20
  5. [XSLT] Différence entre apply-templates et call-template
    Par Cpt.FLAM dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 04/04/2005, 18h47

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