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

C++ Discussion :

Les traits en C++


Sujet :

C++

  1. #1
    Membre éclairé
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2016
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Août 2016
    Messages : 32
    Par défaut Les traits en C++
    Hello à tous !!

    Est-ce quelqu'un pourrait m'expliquer la notion des traits ? Je trouve ça très abstraits et j'aimerais savoir dans quel situation on s'en sert.

    Mercii !!

  2. #2
    Membre très actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par défaut pas compris
    Je développe beaucoup en C++ et je ne vois absolument pas de quoi tu veux parler... Mais regarde le tuto "Présentation des classes de Traits et de Politiques en C++".
    Cela n'a pas l'air d'être un concept très utilisé en C++, si tu es débutant ne te focalise pas dessus.

  3. #3
    Membre éclairé
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2016
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Août 2016
    Messages : 32
    Par défaut
    Ca marche, en fait c'est un concept que j'avais vu en cours c'est pour ça et je n'avais pas très bien compris la notion.
    En industrie, il faudrait se focaliser plus sur l'approche Orienté Objet ?

  4. #4
    Membre éclairé Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Par défaut
    Je dirais que ça dépend de ton problème. Si les classes de traits te permettent de simplifier ton code, utilise-les. Je n'ai presque jamais utilisé les classes traits (peut-être que j'aurais pu/du le faire), mais beaucoup plus souvent les classes de politiques qui me sont extrêmement utiles pour apporter du code depuis l'extérieur d'une fonction.

    Edit: Je ne sais pas si c'est à proprement parler une classe de traits, mais je place presque toujours des alias de type dans mes classes, certains en public. Ca m'est également extrêmement utile pour récupérer de l'information de type depuis l'extérieur. La classe fait pleins d'autres choses qu'établir des correspondances de types, donc je ne sais pas comment qualifier cet usage.

    Quoiqu'il en soit mon -énorme- erreur de débutant avait été de connaître et d'utiliser uniquement la programmation orienté objet pour mettre de la flexibilité dans le code. Ca c'est retourné contre moi en très peu de temps, car si on ne connait que la POO on finit par écrire du code très compliqué, avec des hiérarchies de classes énormes et bien rigides, où rien ne veut plus rien dire . L'héritage est une relation de dépendance très forte donc prudence, que tu sois en industrie ou pas

    Ce forum m'a appris à plutôt aller voir du côté des templates, et ça m'a bien simplifié la vie !

    Bon courage,

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    C'est un concept abstrait puisque ça touche à la méta-programmation.

    Un trait/tag/politic sera un type que tu passes en template pour paramétrer un objet.
    Par exemple le 3° paramètre de std::map qui définit l'opérateur de comparaison, en le modifiant tu changes l'ordre d'insertion/de stockage des éléments de ta map.
    Autre exemple simplet, changer le type de logging selon un trait
    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
    class LogToFile {
    public:
      LogToFile() { mFile.open("log.txt");
      void log(const char* str) { mFile<<str; }
    private:
      std::ofstream mFile;
    };
    class LogToCout {
    public:
      void log(const char* str) { std::cout << str; }
    };
    class NoLog {
    public:
      void log(const char*) {}
    };
    template<class Log>
    class Logger {
    public:
      void log(const char* str) { mLog.log(str); }
     
    private:
      Log mLog;
    };
    Au lieu d'une spécialisation via NoLog, on pourrait spécialiser le Logger pour void
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<>
    class Logger<void> {
    public:
      void log(const char*) {}
    };
    Et tu as tout plein de spécialisation pour avoir des infos sur les types via type_traits.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Membre très actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par défaut
    Ce que l'on appelle trait/tag/politic c'est juste l'utilisation d'un template ?

  7. #7
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Bizarre, il me semble l'avoir expliqué il y a pas longtemps.
    Dans tous les cas, cela sert à l’écriture de code générique (template).
    .
    .
    .
    Message retrouvé dans un forum concurrent::


    tag et politiques sous-entendent des choses différentes, en plus de traits.

    Un trait va renvoyer une info sur un type (cf l'itérator trait) -- le type peut être un tag. Un tag est une structure vide qui va servir à dispatcher via spécialisation template & cie. Une politique ressemble au trait sauf qu'il y a un comportement en plus attaché -- cf le vieux /C++ Modern Design/ d'Andrei Alexandrescu.

    Ca sert tous les jours quand on utilise des vecteurs, mais ce n'est pas visible de l'utilisateur final. De temps en temps je m'en sers industriellement, mais une fois de plus, c'est pour écrire du code générique de type boute à outils. Tout le monde n'a pas mettre les mains dedans.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

    Informations professionnelles :
    Activité : aucun

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

    De manière générale, un trait est une sorte "d'adaptateur" qui permet de déterminer quel sera le type réel d'un terme clairement défini.

    Par exemple, si je crées un trait proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename V, R = V>
    struct MyTrait{
        using value_type = V;
        using return_type = R
    };
    et que je l'utilise sous la forme deusing IntTrait = MyTrait<int>;, les types représentés par IntTrait::value_type et celui de IntTrait::return_type seront tous les deux équivalents de int.

    Par contre, si je l'utilise sous la forme de using IntDoubleTrait = MyTrait<int, double>; le type représenté par IntDoubleTrait::value_type correspondra à int et celui représenté par IntDoubleTrait::return_type sera équivalent à double.

    Et je pourrais très bien en fournir une spécialisation proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <>
    struct MyTrait<std::map<int, std::string>, std::map<int, std::string>>{
         using value_type = int;
         using return_type = typename std::map<int, std::string>::const_iterator;
    };
    A partir de là, vient la notion de politic permet de définir l'interface et -- le cas échéant -- des comportements adaptés à certaines situations et / ou à certains types de données. En cas de besoin, elles peuvent sans aucun problème faire appel à des traits afin de déterminer le type de certains éléments.

    Par exemple, je pourrais créer une politique proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template <typename V, typename R = V>
    Policy{
        static R foo(V const & a, V const & b);
    };
    qui exposera une fonction foo prenant deux paramètres de type V sous la forme de référence constante et qui renverra un élément de type R.

    Mais si je veux l'utiliser avec une std::map<int, std::string>, je vais avoir quelque problèmes, parce que R et V ne correspondent finalement à rien dans une std::map.

    Je vais donc passer par l'adaptateur (mon trait MyTrait) que j'ai "justement" spécialisé pour le traitement de cette drole de bête;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <typename V, typename R = V>
    Policy{
        usign value_type = typename MyTrait<V, R>::value_type;
        using return_type = typename MyTrait<V, R>::return_type;
        static R foo(V const & a, V const & b);
    };
    Et devines quoi? la magie opère :
    • si j'utilise Policy avec un (ou deux) int comme paramètre template, Policy::value_type et Policy::return_type seront tous les deux équivalent au type int
    • si j'utilise Policy avec un int et un double, Policy::value_type sera équivalent à int et Policy::return_type sera équivalent à double
    • si j'utilise Policy avec un (ou deux) std::map<int, std::string>, Policy::value_type sera équivalent à... int et Policy::return_type sera équivalent à ... std::map<int, std::string>::const_iterator


    Il n'y a plus que la notion de tag à voir.

    Tu le sais sans doute, chaque paramètre template de ton expression (template ) intervient dans l'évaluation finale. Par exemple,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename T, typename U>
    struct MyStruct{
        T x;
        U y;
    };
    te définira des types différents si T et/ou U sont de types différents:
    • MaStruct<int, double> S1 et MaStruct<int, double> S2 définis des données de même type parce que les paramètres template sont identique deux à deux, mais
    • MaStruct<int, int> S3 et MaStruct<int, double> S4 définis des données de type différent, parce qu'il y a (au moins) un paramètre template qui diffère.


    Cela nous conviendra très souvent parfaitement. Mais, il y a quelques circonstances dans lesquelles on pourrait souhaiter que S1 et S2 correspondent à des données... de type différents. Ne serait-ce que parce que ma structure MyStruct peut servir à représenter une quantité invraissemblable de données qui n'ont rien à voir les unes avec les autres, même lorsque x est un int et que y est un double.

    Il me faut donc disposer d'un moyen de faire la différence entre une MyStruct<int, double> qui représente respectivement le maximum de vie et le niveau "courant" de vie et une MyStrut<int, double> qui représente respectivement le niveau maximum de mana et ... le niveau courant de mana.

    C'est très simple à faire : il me suffit de rajouter un paramètre template (un "tag") à MyStruct. C'est un élément qui ne sert à rien d'autre qu'à... permettre de faire la distinction entre une MyStruct<int, double> et une autre MyStruct<int, double> qui sera utilisée dans un contexte différent:

    Si nous avons deux données pour lequel ce dernier paramètre template est identique, nous aurons affaire à deux donées de type identique, que nous pourrons utiliser "conjointement". Si ce dernier paramètre template est différent, nous devrons utiliser nos données dans des contextes différnts.

    Citation Envoyé par Matthieu76 Voir le message
    Ce que l'on appelle trait/tag/politic c'est juste l'utilisation d'un template ?
    Ce que l'on appelle trait et politic sera souvent un élément template, avec ou sans spécialisation partielle ou totale.

    Pour ce qui est des tags, qui n'ont -- comme je viens de l'expliquer -- pour seul objectif que de permettre de faire la distinction entre deux spécialisation d'une classe ou d'une structure en cas de besoin, le seul impératif, c'est qu'ils soient représentés par "quelque chose" qui est connu par le compilateur.

    Cela peut être:
    - une valeur numérique entière connue comme une constante de compilation, par exemple au travers d'un code proche de
    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
     
    enum Characteristics{
        live,
        mana,
        strenght,
        agility,
        /*...*/
    };
    template <typename T, typename U, int Tag>
    struct MyStruct{
        T x;
        U y;
    };
    using live_infos = MyStruct<int, double, live>;
    using mana_infos = MyStruct<int, double, mana>;
    using strength_infos = MyStruct<int, double, strenght>;
    using agility_type = MyStruct<int, double, agility>;
    Ou cela peut être un type de donnée (une structure), à ceci près que, comme cela ne servira qu'à la compilation, il ne sert absolument à rien qu'il contienne des données. Nous pourrons donc définir des structures vides pour représenter nos différents tags, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct LiveTag{};
    struct ManaTag{};
    struct StrenghtTag{};
    struct AgilityTag{};
    using live_infos = MyStruct<int, double, LiveTag>;
    using mana_infos = MyStruct<int, double, ManaTag>;
    using strength_infos = MyStruct<int, double, StrenghtTag>;
    using agility_type = MyStruct<int, double, AgilityTag>;
    et nous obtiendront un résultat exactement équivalent.

    L'énorme avantage des structures vides, c'est qu'il est tout à fait possible de rajouter un tag (et l'alias de type qui va avec pour les informations) à peu près n'importe où dans le code, sans avoir besoin d'aller modifier l'énumération, et donc de mieux respecter l'OCP.

    Mais, comme rien n'est gratuit en ce bas monde, cet avantage présente également l'inconvénient de -- justement -- "éparpilller" les différents tags dans le code; même s'il est "tout à fait possible" de les regrouper dans un fichier d'en-tête unique
    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

  9. #9
    Membre éclairé
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2016
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Août 2016
    Messages : 32
    Par défaut
    C'est parfait merci beaucoup pour l'explication !!

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

Discussions similaires

  1. Supprimer Tous les traits?(Shapes)
    Par jojo86 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 12/01/2010, 16h43
  2. Colorier une image sans effacer les traits
    Par msarahm dans le forum Débuter
    Réponses: 2
    Dernier message: 19/10/2008, 23h52
  3. Réponses: 6
    Dernier message: 16/01/2007, 21h34
  4. Comment utiliser les traits?
    Par Pragmateek dans le forum C++
    Réponses: 11
    Dernier message: 11/03/2006, 19h13

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