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 :

Implémentation des std::stream avec variadic template


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 33
    Points : 28
    Points
    28
    Par défaut Implémentation des std::stream avec variadic template
    Bonjour,

    Je me lance dans l'univers fabuleux de C++0x et je voulais changer mon logger pour qu'il utilise les variadic template au lieu du chainage d'appel comme actuellement:
    Logger(Error) << "test" << 4 << 5.f;
    L'operateur surchargé << écrit dans un stream.

    Je me pose 2 questions:
    -existe-t-il une version variadic des streams standards. Genre stream.push(...on metautantdeparamsquonveutici)
    -est-ce que cette technique ne va pas faire grossir mon executable ?
    (Si le compilo génère un prototype de fonction à chaque appel du logger ou presque)

    Matt

  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,

    Peut être que dans un premier temps - avant de chambouler tout le code de la classe logger - serait-il suffisant de wrapper l'appel dans une fonction libre variadique récursive ? Qqchose du genre :

    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
    29
    30
    31
    32
    33
    34
    35
    #include <iostream>
    #include <string>
     
    struct Logger
    {
      template<typename T>
      Logger& operator << (const T& val)
      {
          std::cout << val << std::endl;
          return *this;
      }
    };
     
    template <typename T>
    void log(Logger& l, T&& val)
    {
       l << std::forward<T>(val);
    }
     
    template <typename Head, typename... Tail>
    void log(Logger& l, Head&& head, Tail&&... tail)
    {
        log(l << std::forward<Head>(head), std::forward<Tail>(tail)...);
    }
     
     
    int main()
    {
        int i = 0;
        float f = 5.0f;
        std::string s = "toto";
     
        Logger l;
        log(l, i, f, s, 1, 6.0, "titi");
    }
    -existe-t-il une version variadic des streams standards. Genre stream.push(...on metautantdeparamsquonveutici)
    Pas à ma connaissance.

    -est-ce que cette technique ne va pas faire grossir mon executable ?
    (Si le compilo génère un prototype de fonction à chaque appel du logger ou presque)
    Bonne question. Qui n'est jamais réellement abordé dans les articles/proposal/post sur forum tournant autour des templates variadiques
    J'imagine que pour une utilisation classique (comme montré plus haut, avec des appels récursifs dépilant les arguments un par un), tout le monde compte sur le fait qu'un bon compilateur doit pouvoir assez facilement inliner tous les appels récursifs... mais j'en mettrais pas ma main à couper

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

    N'étant pas encore trop familier du monde des rvalues references en c++0x, si tu pouvais expliquer leur fonctionnement ici, mais aussi l’intérêt de les utiliser. Ou encore l'emploi de std::forward que je ne connaissais pas encore jusque là.

    Je sais que peut être des questions ci-dessus certaines sont s'en doute mal tourner, mais j'ai un peut de mal avec tous ces T&&

    Merci de ta compréhension!

    P.S : j'ai regarder sur ce site FAQ c++0x qui explique de façon claire et concise le prochain standard, mais la pour les rvalues je sèche...

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 33
    Points : 28
    Points
    28
    Par défaut
    merci pour ta réponse rapide arzar. La classe "Logger" que je modifie est une classe perso donc ca pose aps de pb que je la modifie (mais je pensais faire eun wrapper comme tu dis par souci de compatibilité / tests).

    Dommage que tu n'aies pas de réponse sur la taille de l'exécutable, je suppose qu'il faudrait tester.
    Inliner est-il une solution ? Il me semble que le compilo copie le code plutôt que de générer la fonction, le résultat peut s'avérer encore plus gros que s'il avait généré la fonction ! non ?

  5. #5
    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 teto Voir le message
    Inliner est-il une solution ? Il me semble que le compilo copie le code plutôt que de générer la fonction, le résultat peut s'avérer encore plus gros que s'il avait généré la fonction ! non ?
    S'il s'agit d'une combinaison utilisée qu'une seule fois, alors le passage par fonction a peu d'intérêt. Ou si le code 'utile' est plus petit que le passage par fonction (avec l'empilement des paramètres, la préparation de la pile, puis le dépilement, le saut et le retour). Ou si le compilateur sait faire des optimisations car tout est dispo. etc. Bref, difficile de dire à priori si inline va générer un code plus ou moins important.

    Ceci dit cette remarque porte en implicite un à-priori qui fait des ravages en C++ (embarqué en particulier) : Non, les génériques ne génèrent pas du code bloat !!!! Pas plus que de créer 45000 surcharges et/ou classes avec des param différents mais impliquant une violation du DRY (don't repeat yourself) et une production du code y compris pour ce qui n'est pas utilisé !!!

    Enfin question de curiosité : pourquoi remplacer un système de log qui ressemble à des flux (et qui semble assez naturel) par un système par appel de fonction ? Pour l'exercice de style ?

Discussions similaires

  1. Implémentation d'un singleton avec des std::shared_ptr
    Par whityranger dans le forum SL & STL
    Réponses: 17
    Dernier message: 10/01/2014, 12h04
  2. Réponses: 10
    Dernier message: 12/09/2007, 11h15
  3. Réponses: 1
    Dernier message: 30/08/2006, 18h15
  4. Réponses: 1
    Dernier message: 26/06/2006, 12h33
  5. Réponses: 3
    Dernier message: 13/08/2004, 19h52

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