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 :

pimpl et template


Sujet :

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 290
    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 290
    Billets dans le blog
    2
    Par défaut pimpl et template
    Bonjour,

    imaginons que nous travaillons sur une bibliothèque. Nous voulons donc, idéalement, exporter un seul en-tête qui propose le protocole (ensemble des fonctions et variables publiques) et cacher l'implémentation en elle même.
    Pour ce faire, rien de tel qu'un classique pimpl:
    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
    /***** my_lib.h ********/
     
    class MyLibImpl;
     
    class MyLib
    {
    public:
     
    // protocol
       void DoSomething();
    // ...
     
    private:
       MyLibImpl * pimpl_; // pimpl: tout sera implémenté dans cette classe
       int a_super_important_value;
    };
     
    /***** my_lib.cpp ********/
    #include "my_lib.h"
    #include "my_lib_impl.h"
     
    void MyLib::DoSomething()
    {
       pimpl->DoSomething();
    }
    Vous noterez la présence de cette variable membre privée: a_super_important_value. Elle est type int.

    Donc imaginons que nous avons implémenté notre lib, que ça marche qu'on est prêt à lancer des tests en pré-prod. Et là, subitement, le commercial nous appelle et nous explique que finalement, cette super_important_value ne sera pas forcément un entier, mais d'un type indéterminé (donc pas forcément natif) que le client doit pouvoir choisir. Les commerciaux sont très forts, et dans cette situation hypothétique, nous nous sommes laissé convaincre, sans même s'en rendre compte, que c'était une bonne idée, et c'était pas bien grave de prévenir alors que le code était finit.

    Ok donc, pas de problème, grâce au c++ on peut tout faire. Pour ce problème là, on a les templates. Je vais transformer ma classe en template et ça va rouler tout seul:
    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
    /***** my_lib.h ********/
     
    class MyLibImpl;
     
    template <typename T>
    class MyLib
    {
    public:
     
    // protocol
       void DoSomething();
    // ...
     
    private:
       MyLibImpl * impl_; // pimpl: tout sera implémenté dans cette classe
       T a_super_important_value;
    };
    Sauf que non, on me fait signe que c'est pas possible! Et pour une raison toute bête: le code d'une classe template doit être dans l'en-tête (ou inclure le cpp à la fin de l'en-tête ce qui revient au même). Et donc ça casse mon pimpl.

    Savez-vous quelles sont les solutions pour se sortir de cette situation à peu de frais?

  2. #2
    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, ce qui importe dans pimpl, c'est l'interface de ta classe qui le gère... Le fait que le code qui permet l'appel des différentes fonctions soit dans un fichier cpp ou dans le fichier d'en-tête pour cause de besoin d'inlining ne pose pas vraiment de problème majeur.

    Le problème auquel tu pourrait éventuellement être confronté, c'est si tu t'apprêtes à fournir une bibliothèque dynamique et qu'il faut que tout le code correspondant soit bel et bien accessible depuis la bibliothèque.

    Dans ce cas, je partirais sans doute du principe que le type de a_super_important_value doit, quoi qu'il en soit, proposer une interface propre (sans doute proche de ce que l'on peut obtenir avec des valeurs numériques), et j'envisagerais l'utilisation de l'instanciation explicite pour "tout type connu correspondant" à cette interface, en gardant en tête le fait que cela correspondra à une augmentation sans doute substantielle de taille de la bibliothèque...
    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

  3. #3
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    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 290
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par koala01 Voir le message
    De manière générale, ce qui importe dans pimpl, c'est l'interface de ta classe qui le gère... Le fait que le code qui permet l'appel des différentes fonctions soit dans un fichier cpp ou dans le fichier d'en-tête pour cause de besoin d'inlining ne pose pas vraiment de problème majeur.
    En fait non, ce qui importe dans mon cas, c'est que l'en-tête que je fournis (MyLib.h) ne doit inclure aucun autre fichier de ma lib. Car l'idée c'est de fournir au client le .lib/.a (ce sera une lib statique et pis c'est tout) et un seul et unique en-tête. Si MyLib.h inclus d'autres en-têtes, il faut alors fournir ces en-têtes également, et c'est ce que je souhaite éviter.

  4. #4
    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
    La question est alors : de quels type est susceptible d'être a_super_important_value

    A priori, les types devraient ne pas être si nombreux que cela dans le sens où cette variable était prévue à l'origine pour être une valeur numérique entière.

    Je serais donc relativement surpris si tu devais prévoir beaucoup plus que les treize types primitifs et quelque chose ressemblant à std::complex.

    Dans de telles conditions, tu devrais pouvoir envisager l'instanciation explicite pour ces différents types et donc considérer les implémentations des différentes fonctions comme internes (en n'incluant le fichier qui les implémente que dans le fichier qui provoque l'instanciation explicite )
    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

  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
    Sinon y'a peut-être une "astuce" crade pour éviter le template, qui est de mettre a_super_important_value en void*
    En fournissant qqs méthodes pour manipuler ça (une méthode template qui réalise le transtypage par exemple).

    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
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    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 290
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par koala
    Dans de telles conditions, tu devrais pouvoir envisager l'instanciation explicite pour ces différents types
    Tu as dû louper 4 mots dans mon message initial:
    Savez-vous quelles sont les solutions pour se sortir de cette situation à peu de frais?


    Non mais plus sérieusement, le problème c'est qu'apparemment, ils veulent y injecter des objets à eux, et je n'ai pas la moindre idée de ce que ça peut être. La seule chose que je sais, c'est que ces objets implémenterons les opérateurs de bases (+,-,*,/) ainsi que les opérateurs de flux.

    Citation Envoyé par Bousk Voir le message
    Sinon y'a peut-être une "astuce" crade pour éviter le template, qui est de mettre a_super_important_value en void*
    En fournissant qqs méthodes pour manipuler ça (une méthode template qui réalise le transtypage par exemple).

    Herb Sutter dit que cette méthode c'est très beaucoup pas bien!
    Mais bon, j'ai peur que ce ne soit la seule solution malheureusement

  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
    Tu peux peut-être utiliser le triplet interface + template + static_assert (ou boost::concept, je crois)

    Puis définir une classe de Nombre et des wrappers directs pour les types de bases
    Il te suffirait d'avoir un pointeur de ce Nombre

  8. #8
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    En fait, tu dois

    1. separer tout ce qui est pas dependant du type en paramettre dans des types non-template (par exemple si l'implementation a pas besoin du type, tu peux garder un pointeur ca ira)
    2. avoir tout ce qui est dependant du type dans le header.

    Donc on peut pas te repondre clairement sans savoir si a_super_important_value est exploite dans toutes les methodes de MyLibImpl.

    Si oui, alors t'as pas d'autre choix que je tout ecrire en template.
    Si non, alors tu as une separation claire entre le code qui en a besoin et le reste. Mets le reste dans les cpp, et le code dependant du type dans le header.

  9. #9
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Déclarer a_super_important_value de type boost::any peut être une solution rapide à mettre en place.
    Le principal inconvénient est que l'utilisateur de la lib devra compiler avec boost.

  10. #10
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    A mon avis, le problème se situe dans le cahier des charges plus que dans le code lui-même. Si on ne sait pas à l'avance quels types circulent dans notre API, c'est que le besoin du client n'est pas suffisamment bien défini, point.

Discussions similaires

  1. [Templates] Quel système utilisez-vous ? Pourquoi ?
    Par narmataru dans le forum Bibliothèques et frameworks
    Réponses: 270
    Dernier message: 26/03/2011, 00h15
  2. Template XHTML
    Par Sylvain James dans le forum XSL/XSLT/XPATH
    Réponses: 14
    Dernier message: 16/06/2003, 21h45
  3. appliquer plusieurs templates
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 04/04/2003, 16h26
  4. template match="node() mais pas text()"
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 26/03/2003, 10h52
  5. [XSLT] template
    Par demo dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 09/09/2002, 11h31

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