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 :

[exercice] template et wrapper


Sujet :

Langage C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut [exercice] template et wrapper
    Allez, encore un petit

    Nous avons une classe MyOuput dont le rôle consiste à afficher des valeurs sur la console. Pour diverses raisons spécifiques au cahier des charges, une fonction print() existe pour chaque type que nous souhaitons accepter. Pour d'autres raisons variées, encore spécifiques au cahier des charges, nous décidons de créer une couche d'abstraction supplémentaire, un wrapper, qui lui va gérer le problème en utilisant une fonction template:

    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
    #include <iostream>
    #include <string>
    using namespace std;
     
    struct MyOutput
    {
    	void print(const string & value) const { cout << "string: " << value << endl; }
    	void print(bool value) const { cout << "bool: " << value << endl; }
    };
     
    struct Wrapper
    {
    	template <typename T>
    	void print(const T & value) const { my_output_.print(value); }
     
    private:
    	MyOutput my_output_;
    };
     
    int main()
    {
    	Wrapper my_wrapper;
    	my_wrapper.print("test");
    	my_wrapper.print(false);
     
    	getchar();
    	return 0;
    }
    Questions:
    Quel est l'output de ce programme?
    Pourquoi?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Encore plus vicieux ^^

    Tel quel, le code affiche un booléen pour "test", car "test" est un char * et non un std::string. Un char * est plus facilement convertible en bool (ou int) par la promotion d'entier qu'en std::string (convertion implicite avec un constructeur qui a un seul argument).

    C++ "traîne" derrière lui son héritage C. Cela peut être commode (réutilisation de code) mais est aussi incroyablement dangereux, comme ici.
    Pour éviter ceci, il faut utiliser uniquement std::string.

    Et donc le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my_wrapper.print("test");
    devrait être :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my_wrapper.print(std::string("test"));
    ou en C++14 (il me semble) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my_wrapper.print("test"s);
    ou en C++11 avec le « user-defined literals » qui va bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my_wrapper.print("test"_s);
    Demander ça à l'utilisateur n'est pas raisonnable et donc il faut fournir une surcharge pour char * :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void print(char const * const value) const { std::cout << "string: " << value << std::endl; }
    PS : Il manque tous les std:: aux cout et endl.

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Encore plus vicieux ^^

    Et encore excellente réponse de ta part

    Citation Envoyé par Ehonn Voir le message
    Un char * est plus facilement convertible en bool
    Histoire d'ajouter une précision, c'est parce qu'un char * est un pointeur. Donc mon exemple fonctionne avec n'importe quel type de pointeur en fait.
    A noter que le wrapper et l'histoire de template ne sont là, encore une fois, que pour brouiller les pistes.

    Citation Envoyé par Ehonn Voir le message
    PS : Il manque tout les std:: au cout.
    Damned! Je vais corriger ça tout de suite. Merci
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Quitte à préciser que char* est un pointeur, rajoutons que bool est un entier (si si...) et que tout "non-0" est vrai.
    Comme 0 est une adresse invalide, strictement jamais attribuée, le code affichera nécessairement "bool: 1", c'est à dire print(true)

    Les chemins de conversions envisageable pour cette surcharge est:
    const char* > int > bool
    const char* > implicite std::string(const char*)

    Avec, comme indiqué, la règle que sera préférée les conversions à la construction.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Ça me rappelle une règle de codage que j'ai eu un jour:
    Bien que les strings soient sexys, il a toujours quelqu'un pour refuser d'en utiliser.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par leternel Voir le message
    Quitte à préciser que char* est un pointeur, rajoutons que bool est un entier (si si...) et que tout "non-0" est vrai.
    Attention, j'ai vu récemment que cela n'était valable que pour un Booléen valide (obtenu en le construisant, ou par cast/affectation etc.), et donc garanti contenir seulement 0 ou 1: Un Booléen obtenu par truandage (ou non-initialisation) peut être non-nul et considéré faux, car certains compilos ne testent que le bit de poids faible.

    Si int a=33;, alors (bool)a est valide*, tandis que *reinterpret_cast<bool*>(&a) causera un comportement indéfini.

    *Si ça marche comme pour les flottants, reinterpret_cast<bool>(a) devrait également faire la conversion valide.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    d'un autre côté, rencontrer des problèmes quand on en est au *cast*, c'est un peu normal.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

Discussions similaires

  1. Réponses: 7
    Dernier message: 08/07/2010, 10h36
  2. appliquer plusieurs templates
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 04/04/2003, 16h26
  3. template match="node() mais pas text()"
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 26/03/2003, 10h52
  4. [XSLT] template
    Par demo dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 09/09/2002, 11h31
  5. Pouvez vous m'aider a resoudres ces 3 exercices
    Par algorithmique dans le forum Algorithmes et structures de données
    Réponses: 11
    Dernier message: 09/08/2002, 17h26

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