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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    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?

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

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    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é
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    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

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    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.

  5. #5
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    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.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    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

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par défaut
    d'un autre côté, rencontrer des problèmes quand on en est au *cast*, c'est un peu normal.

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