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 :

Template : récupérer le type de base en c++0x


Sujet :

Langage C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut Template : récupérer le type de base en c++0x
    Bonjour,

    Sur un des tutos de Laurent Gomilla, http://loulou.developpez.com/tutorie...eur3d/partie7/, il est proposé une méthode pour extraire le type de base d'un autre type, en sortant référence et const :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename T> struct Base {typedef T Type;};
    template <typename T> struct Base<T&> {typedef T Type;};
    template <typename T> struct Base<const T> {typedef T Type;};
    template <typename T> struct Base<const T&> {typedef T Type;};
     
    // Base<int>::Type équivaut à int
    // Base<const int&>::Type équivaut également à int
    // etc...
    Mais je me suis dis qu'il doit surement avoir l'équivalent en c++0x, donc je vais de ce pas faire un tour dans la documentation de boost sur typetrait ici boost sur typetrait ici, mais je n'arrive pas à trouver quelque chose de correspondant.

    Si quelqu'un peut m'indiquer s'il connaît, où pour confirmer qu'il faudrait utiliser conjointement std::remove_const et std::remove_reference, je serais reconnaissant!

    Je suis sous g++-4.6. Merci d'avance Bonne journée!

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,

    Le C++ supporte l'héritage multiple donc ça n'a pas vraiment de sens de parler du "type de base d'un autre type"..

    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct A{};
    struct B{};
    struct C : public A, public B{};
    struct D{}:
    struct E{};
     
    struct F : public C, public D, public E{};
    {};
    Que est le "type de base de F" ? A, B, C, D ou E ? Tout à la fois ?

    Donc non, ce n'est pas possible. En revanche, il existe en C++0x et dans boost un trait qui permet de tester si un type est parent d'un autre, il s'agit du trait std::is_base_of :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::cout << std::is_base_of<A, F>::value // affiche "1"

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    Ah oui pardon je me suis mal exprimé

    Quand je parlais du type de base je faisais l'analogie avec le tutoriel cité en début de poste, à savoir récupéré le type sans certains attributs comme const, ou encore retirer les références :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename T> struct Base {typedef T Type;};
    template <typename T> struct Base<T&> {typedef T Type;};
    template <typename T> struct Base<const T> {typedef T Type;};
    template <typename T> struct Base<const T&> {typedef T Type;};
     
    // Base<int>::Type équivaut à int
    // Base<const int&>::Type équivaut également à int
    // etc...
    Mais cela de façon factoriser, avec des trais standards par exemples!

  4. #4
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Pour faire ca il faut que tu regardes dans le header type_traits , par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    template<class> struct remove_const;
    template<class> struct remove_reference;
    template<class> struct remove_pointer;

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    Merci, j'ai regardé et je pense que c'est bien ce qu'il me faut!

    Bonne journée!

  6. #6
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Oh bon sang désolé j'étais complètement à coté de la plaque.

    Outre les deux traits mentionnés par Flob90, tu peux aussi t'intéresser à std::remove_cv qui, grossièrement, supprime les const et volatile et surtout std::decay qui semble être une combinaison de std::remove_reference et std::remove_cv. C'est ce qui semble se rapprocher le plus d'un trait qui permettant de retrouver "le type de base" (sauf que std::decay semble aussi gérer certain cas particulier comme les tableaux et les fonctions)

  7. #7
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @Arzar: En C++, decay se réfère au fait de passer des tableaux ou des fonctions à des pointeurs, de T[] à T* par exemple. Je pense que ce type traits (decay) est fait pour ca, le sortir pour autre chose c'est un peu gros je pense, et ca ne répondra pas nécessairement aux besoins.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    En fait j'essaie d'utiliser une combinaison des deux traits std::remove_const et std::remove_reference, j'y arrive mais pas en une seule ligne comme dans l'exemple 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
    #include <type_traits> 
     
    typedef const int& Actuel;
     
    int main()
    {
        typedef typename std::remove_reference< Actuel >::type noRef;
        typedef typename std::remove_const< noRef >::type noRefConst1;
     
        typedef typename std::remove_reference< typename std::remove_const<Actuel>::type >::type noRefConst2;
     
     
        noRefConst1 a;
        noRefConst2 b;
     
        return 1;
    }
    Lorsqu'on compile le code il plante lors de l'initialisation de b, mais pas de a, preuve qu'on ne retire pas bien le const ou la reference.

    Merci pour vos réponse!

  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
    Bonjour,

    std::remove_reference< std::remove_const<T>> n'est pas équivalent à std::remove_const< std::remove_reference<T>>.

    Il faut bien essayer d'enlever d'abord les références puis les qualificatifs cv :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef std::remove_const< std::remove_reference<Actuel>::type >::type noRefConst3;


    P.S. : j'imagine qu'il s'agit d'une erreur de copier/coller, mais typename ne doit pas être utilisé en dehors d'un générique

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    Oui pardon les typenames viennent de la classe template..

    Par contre bonne nouvelle c'était bien ça

    Mais avant de finir si tu pouvais m'expliquer pourquoi il fallait d'abord enlever la référence puis le const? Et pas l'inverse?

    Merci à tous!

  11. #11
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Flob90
    @Arzar: En C++, decay se réfère au fait de passer des tableaux ou des fonctions à des pointeurs, de T[] à T* par exemple. Je pense que ce type traits (decay) est fait pour ca, le sortir pour autre chose c'est un peu gros je pense, et ca ne répondra pas nécessairement aux besoins.
    Oui, je connais le sens usuel de decay en C++, mais pour le trait std::decay le sens usuel a été un peu bousculé pour permettre non seulement de transformer des types tableaux et fonction en pointeur vers élément et pointeur de fonction mais aussi pour servir de raccourci à std::remove_reference/std::remove_cv. Ce n'est pas overkill, c'est fait pour.

    Citation Envoyé par N3242
    Let U be remove_reference<T>::type.
    If is_array<U>::value is true, the member typedef type shall equal remove_extent<U>::type*.
    If is_function<U>::value is true, the member typedef type shall equal add_pointer<U>::type.
    Otherwise the member typedef type equals remove_cv<U>::type. [Note: This behavior is similar to the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions applied when an lvalue expression is used as an rvalue, but also strips cv-qualifiers from class types in order to more closely model by-value argument passing. —end note ]
    Par exemple dans le code source de libc++, on peut voir que std::decay est utilisé assez souvent (pour implémenter bind, function, future, thread, pair et tuple) dans ce sens.

    Ou encore ici
    In addition, I'll like to mention that std::decay typically works as a shortcut for remove_cv<remove_refernence<...>>

  12. #12
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @Arzar: J'avais lu mais pas vu ca comme ca. Par contre ca dépends quand même de ce que l'op entend comme type de base pour T[] par exemple, si pour lui c'est T alors decay ne convient pas.

  13. #13
    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,
    Citation Envoyé par victor_gasgas Voir le message
    Mais avant de finir si tu pouvais m'expliquer pourquoi il fallait d'abord enlever la référence puis le const? Et pas l'inverse?
    Je le comprend comme ça :
    Imagines que tu remplace la référence par un pointeur constant : typedef const int*const Actuel;
    Premier scénario :
    Tu enlèves d'abord const cela donne const int *
    Puis tu enlèves le pointeur => const int

    Second scénario
    Dans l'autre sens, tu enlèves d'abord le pointeur => const int
    Puis le const => int

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    Merci pour ces explications!

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 23/09/2014, 17h13
  2. [PHP 4] Récupérer les types d'une base
    Par pek.plus.ultra59 dans le forum Langage
    Réponses: 2
    Dernier message: 04/05/2009, 08h59
  3. Utilité de récupérer le type d'un template
    Par Flo. dans le forum Langage
    Réponses: 7
    Dernier message: 01/02/2009, 11h47
  4. [CR]Changement de type de base de donnée
    Par nabil dans le forum SAP Crystal Reports
    Réponses: 1
    Dernier message: 12/04/2004, 22h42
  5. Récupérer le type de démarrage d'un service
    Par Nathan dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 09/04/2004, 15h07

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