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 :

overload operator stream


Sujet :

Langage C++

  1. #1
    Membre régulier
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Points : 99
    Points
    99
    Par défaut overload operator stream
    Bonjour,

    Je cherche à surcharger les operateurs de stream (istream & ostream), pour pouvoir ecrire/lire simplement.

    Voici la classe qui utilisera les surcharges:
    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
        class header
        {
        public:
            typedef std::shared_ptr<header> ptr;
            // --
            static const short_t version_size   = 5;
            static const short_t header_size    = 5;
            // --
            header() : m_version(), m_header() {}
            header(const std::string& v, const std::string& h) :
                m_version(v), m_header(h) {}
            virtual ~header() {}
            std::ostream& operator<<(std::ostream& os);
            std::istream& operator>>(std::istream& is);
            const std::string& version() const { return m_version; }
            const std::string& unique_id() const { return m_header; }
        private:
            std::string m_version;
            std::string m_header;
        };
    Et voici la classe qui va appeler l'operateur:
    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
        template<typename StreamType>
        class pack
        {
        public:
            typedef std::shared_ptr<pack> ptr;
            pack() : m_stream(), m_header() {}
            pack(const pack<StreamType>& p) = delete;
            pack& operator=(const pack<StreamType>& p) = delete;
            virtual ~pack() { m_stream.close(); }
            node::ptr open(fs::path& p)
            {
                m_stream.open(p(false), std::istream::in | std::istream::binary);
                m_stream >> m_header;
    /// ...
                return rootnode;
            }
            const fs::header::ptr header() const { return m_header; }
            StreamType& stream() { return m_stream; }
        private:
            StreamType m_stream;
            fs::header::ptr m_header;
        };
    Et l'erreur ...
    error: cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’|
    Ca doit etre encore simple comme bonjour, mais je ne sais point résoudre
    Que faut-il changer?

    merci,
    nico

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Déjà, une fonction qui s'appelle "open" et qui... lit, ne serait-ce qu'une partie, du fichier ouvert, c'est "moyen moyen"

    Dans le meilleur des cas, une fonction nommée open() devrait se contenter... d'essayer d'ouvrir le flux et de renvoyer un résultat correspondant à la réussite ou à l'échec de cette ouverture, et ce seraient des fonctions respectives "read" et "write" qui devraient s'occuper de la lecture et de l'écriture (quitte à ce qu'elles appellent, elles-mêmes, de fonctions de lecture ou d'écriture plus spécifiques quant au type d'objet à lire/ à écrire)

    C'est d'autant plus vrai que tu places un point de variation au niveau du type de flux utilisé, et que le membre que tu nommes m_stream pourrait donc parfaitement dériver de ... std::basic_ostream<char>, le nom de ta classe (pack) étant suffisamment imprécis que pour laisser planer le doute sur le fait qu'elle ne sert qu'à... lire les données.

    Les tentatives d'ouvrir ce flux en... lecture et d'essayer, par la suite d'y lire des informations risquent, très certainement, de te poser certain problèmes

    Tu pourrait sans doute lever cette ambiguité sur le sens du flux à donner en paramètre (tout en gardant en tete qu'une fonction "open" ne devrait pas mentir sur ce qu'elle fait en essayant de lire et/ ou d'écrire dans le flux qu'elle ouvre) en créant une classe Packer (pour l'écriture) et une classe UnPacker (pour la lecture)

    Dans un autre ordre d'idée, l'utilisation d'une std::string pour représenter un identifiant unique me semble... peu adéquate: Ton identifiant unique va, très certainement, servir peu ou prou à "tout bout de champs" pour récupérer une en-tête particulière ou pour vérifier si l'en-tête courente correspond à celle à laquelle tu t'attends.

    Cela implique que tu auras (sans doute) de très nombreuses comparaison au niveau de cet identifiant unique. Or, la comparaison de chaine de caractères est, très certainement, le genre de comparaison qui prend le plus de temps!

    En remplaçant cette chaine de caractères par un entier "aussi grand que possible", tu arriveras surement à gagner énormément de performances à peu de frais.

    Peut etre pourrais tu te tourner du coté de la fonction std::hash (si tu disposes de C++11) pour générer ton identifiant unique

    Un raisonnement sensiblement similaire (la fonction hash en moins) pourrait d'ailleurs très bien être suivi en ce qui concerne la version, vu que, si tu prévois cette information, c'est très certainement afin de pouvoir prendre les évolutions futures en compte, et donc, afin de comparaison

    Ceci étant dit, la solution passe par le fait de déclarer les opérateurs << et >> comme des fonctions amies de ta classe header.

    Je ne sais plus exactement quelle est la raison qui fait que, mais si tu modifies ta classe sous la forme 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
    18
    19
    20
      class header
        {
        public:
            typedef std::shared_ptr<header> ptr;
            // --
            static const short_t version_size   = 5;
            static const short_t header_size    = 5;
            // --
            header() : m_version(), m_header() {}
            header(const std::string& v, const std::string& h) :
                m_version(v), m_header(h) {}
            virtual ~header() {}
            friend std::ostream& operator<<(std::ostream& os, header const & h);
            friend std::istream& operator>>(std::istream& is, header & h);
            const std::string& version() const { return m_version; }
            const std::string& unique_id() const { return m_header; }
        private:
            std::string m_version;
            std::string m_header;
        };
    (en veillant à adapter le code pour appeler h.m_header et h.m_version ), cela devrait pouvoir passer
    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
    Membre régulier
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Points : 99
    Points
    99
    Par défaut
    J'ai tenté ceci:

    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
     
        class header
        {
        public:
            typedef std::shared_ptr<header> ptr;
            // --
            static const short_t version_size   = 5;
            static const short_t header_size    = 5;
            // --
            header() : m_version(), m_header() {}
            header(const std::string& v, const std::string& h) :
                m_version(v), m_header(h) {}
            virtual ~header() {}
            friend std::ostream& operator<<(std::ostream& os, const header& h)
            {
                char vx[header::version_size];
                char hx[header::header_size];
                ::memcpy(vx, h.m_version.c_str(), header::version_size);
                ::memcpy(hx, h.m_header.c_str(), header::header_size);
                os << vx << hx;
            }
            friend std::istream& operator>>(std::istream& is, header& h)
            {
                char* vx = new char[header::version_size];
                char* hx = new char[header::header_size];
                is.read(vx, header::version_size);
                is.read(hx, header::header_size);
                h.m_version = std::string(vx, header::version_size);
                h.m_header = std::string(hx, header::header_size);
                delete[] vx;
                delete[] hx;
                return is;
            }
    dans le header,
    toujours la même erreur.
    Et si je met le code de la fonction dans le cpp, j'obtiens un "friend declared outside of class" un truc dans le genre

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Pourrais tu nous donner TOUTES les erreurs que tu obtiens, car, j'ai fait un rapide test, en fournissant une implémentation "bidon" des opérateurs, et ca fonctionnait chez moi...
    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
    Membre régulier
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Points : 99
    Points
    99
    Par défaut
    Bon, recommencons.


    Les classes:
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
     
    namespace fs
    {
        template<typename StreamType>
        class pack;
        class header
        {
        public:
            typedef std::shared_ptr<header> ptr;
            // --
            static const short_t version_size   = 5;
            static const short_t header_size    = 5;
            // --
            header() : m_version(), m_header() {}
            header(const std::string& v, const std::string& h) :
                m_version(v), m_header(h) {}
            virtual ~header() {}
            std::ostream& operator<<(std::ostream& os)
            {
                char vx[header::version_size];
                char hx[header::header_size];
                ::memcpy(vx, m_version.c_str(), header::version_size);
                ::memcpy(hx, m_header.c_str(), header::header_size);
                os << vx << hx;
                return os;
            }
            std::istream& operator>>(std::istream& is)
            {
                char* vx = new char[header::version_size];
                char* hx = new char[header::header_size];
                is.read(vx, header::version_size);
                is.read(hx, header::header_size);
                m_version = std::string(vx, header::version_size);
                m_header = std::string(hx, header::header_size);
                delete[] vx;
                delete[] hx;
                return is;
            }
            const std::string& version() const { return m_version; }
            const std::string& unique_id() const { return m_header; }
        private:
            std::string m_version;
            std::string m_header;
        };
     
        template<typename StreamType>
        class pack
        {
        public:
            typedef std::shared_ptr<pack> ptr;
            pack() : m_stream(), m_header() {}
            pack(const pack<StreamType>& p) = delete;
            pack& operator=(const pack<StreamType>& p) = delete;
            virtual ~pack() { m_stream.close(); }
     
            node::ptr open(fs::path& p)
            {
                m_stream.open(p(false), std::istream::in | std::istream::binary);
                m_stream >> m_header;
                fs::directory::ptr rootd;
                fs::any::ptr entry;
                fs::node::ptr rootnode;
                m_stream >> rootd;
                auto type(rootd->packing_type());
                if(type == rules::package::packing_types::FolderAny
                       || type == rules::package::packing_types::FolderFramed)
                {
                    read_table<fs::any::ptr>(m_stream, rootd);
                }
                else if(type == rules::package::packing_types::FolderRessource)
                {
                    read_table<fs::file::ptr>(m_stream, rootd);
                }
     
                return rootnode;
            }
     
        private:
            StreamType m_stream;
            fs::header::ptr m_header;
     
            template<typename ChildType>
            void read_table(StreamType& stream, fs::directory::ptr d)
            {
                auto buffer(d->get_buffer<ChildType>());
                for(fs::size_t ci = 0, cl = std::get<0>(buffer); ci < cl; ++ci)
                {
                    ChildType child;
                    stream >> child;
                    std::get<1>(buffer).push_back(child);
                }
                d->set_childs(std::get<1>(buffer));
                for(auto& child: *d)
                {
                    auto type(child->packing_type());
                    if(type == rules::package::packing_types::FolderAny
                       || type == rules::package::packing_types::FolderFramed)
                    {
                        read_table<fs::any::ptr>(stream, child);
                    }
                    else if(type == rules::package::packing_types::FolderRessource)
                    {
                        read_table<fs::file::ptr>(stream, child);
                    }
                    else { throw; }
                }
            }
        };
    }
    Donc je fais ceci, d'un autre fichier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            fs::pack<std::ifstream>::ptr reader;
            m_nodes_old = reader->open(last_compiled_package);
    Build complet:
    Compiling: ../../Tools/fs/updater.cpp
    In file included from /media/data/dev/projects/Tools/fs/updater.h:5:0,
    from /media/data/dev/projects/Tools/fs/updater.cpp:1:
    /media/data/dev/projects/Tools/fs/package.h: In instantiation of ‘fs::node::ptr fs::pack<StreamType>::open(fs::path&) [with StreamType = std::basic_ifstream<char>; fs::node::ptr = std::shared_ptr<fs::node>]’:
    /media/data/dev/projects/Tools/fs/updater.cpp:48:61: required from here
    /media/data/dev/projects/Tools/fs/package.h:117:13: error: cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’
    In file included from /usr/include/c++/4.7/fstream:40:0,
    from /media/data/dev/projects/Tools/fs/fs.h:5,
    from /media/data/dev/projects/Tools/fs/package.h:4,
    from /media/data/dev/projects/Tools/fs/updater.h:5,
    from /media/data/dev/projects/Tools/fs/updater.cpp:1:
    /usr/include/c++/4.7/istream:866:5: error: initializing argument 1 of ‘std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&&, _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::shared_ptr<fs::header>]’
    In file included from /media/data/dev/projects/Tools/fs/updater.h:5:0,
    from /media/data/dev/projects/Tools/fs/updater.cpp:1:
    /media/data/dev/projects/Tools/fs/package.h:121:13: error: cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’
    In file included from /usr/include/c++/4.7/fstream:40:0,
    from /media/data/dev/projects/Tools/fs/fs.h:5,
    from /media/data/dev/projects/Tools/fs/package.h:4,
    from /media/data/dev/projects/Tools/fs/updater.h:5,
    from /media/data/dev/projects/Tools/fs/updater.cpp:1:
    /usr/include/c++/4.7/istream:866:5: error: initializing argument 1 of ‘std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&&, _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::shared_ptr<fs::directory>]’

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Bon, déjà, tu vas me faire le plaisir de virer ces
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                ::memcpy(vx, m_version.c_str(), header::version_size);
                ::memcpy(hx, m_header.c_str(), header::header_size);
    que je ne saurais voir dans l'opérateur <<!!!

    c_str() est une fonction constante qui permet de récupérer le contenu d'une std::string sous la forme d'une chaine de caractères "C style", mais dont le pointeur renvoyé ne peut en aucun cas être modifié.

    A priori, m_version et m_header sont initialisés à des chaines vides lorsqu'il va être question de passer ton objet de type header à l'opérateur <<. Cela signifie que, selon les réglages du compilateur, tu pourrais très bien obtenir un pointeur sur un tableau de ... 0 caractères!!!

    Bonjour la galère si tu essaye d'y copier ne serait-ce qu'un seul byte
    (d'ailleurs, c'est bien simple: gcc 4.8.1 me sort une erreur "error: invalid use of non-static data member 'fs::header::m_version'" à ce sujet )

    Enuite, je ne comprend pas pourquoi je n'ai pas réagit directement, mais, étant donné que tu ouvre le fichier sous une forme (indument nommée) binaire, tu ne peux pas utiliser les opérateurs << et >>, qui sont à utiliser pour les flux formatés.

    Les fonctions que tu dois utiliser lorsque tu ouvres un fichier avec le paramètre std::istream::binary sont:
    1. get()
    2. read()
    3. readsome()
    (et leurs différentes surcharges).

    Enfin, le membre m_header de ta classe pack est (le typedef te l'a peut etre caché ) un ... std::shared_ptr<header>, ce qui signifie que c'est un header * qui est derrière, et non un header &.

    Si tu veux avoir la moindre chance que cela marche (pour autant que tu utilises effectivement un flux formaté, et non un flux binaire), il faut au minimum prendre " ce qui est pointé" par ton shared_ptr, parce qu'il n'existe pas de surcharge pour l'opérateur >> pour les shared_ptr (assez bizarrement, il existe une surcharge pour l'opérateur << mais pas pour >> )

    Une fois ces considérations prises en compte, le fait de déclarer les opérateurs comme amis de la classe permet de s'assurer que tu surcharges bel et bien les fonctions libres équivalentes et un code (je l'ai un peu simplifié pour ne garder que le nécessaire ) 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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <memory>
    namespace fs
    {
        typedef short short_t;
        template<typename StreamType>
        class pack;
        class header
        {
        public:
            typedef std::shared_ptr<header> ptr;
            static const short_t version_size   = 5;
            static const short_t header_size    = 5;
            // --
            header() : m_version(), m_header() {}
            header(const std::string& v, const std::string& h) :
                m_version(v), m_header(h) {}
            virtual ~header() {}
            std::ostream& operator<<(std::ostream& os )
            {
                os << m_version << m_header;
                return os;
            }
            friend std::istream& operator>>(std::istream& is, header & h)
            {
                std::cout<<"reading header"<<std::endl;// juste pour savoir qu'on
                                                       // passe par ici
                is>>h.m_version>>h.m_header;
                return is;
            }
        private:
            std::string m_version;
            std::string m_header;
        };
     
        template<typename StreamType>
        class pack
        {
        public:
            pack() : m_stream(), m_header() {}
            pack(const pack<StreamType>& p) = delete;
            pack& operator=(const pack<StreamType>& p) = delete;
            virtual ~pack() { m_stream.close(); }
     
            void open(std::string const & p)
            {
                m_stream.open(p);
            }
            void readHeader(){
                m_stream>>*m_header;
            }
            /* un très mauvais plan: permettre l'écriture dans cette classe
            void writeHeader()const{
                m_stream<<m_header;
            }
            */
        private:
            StreamType m_stream;
            fs::header::ptr m_header;
     
        };
    }
    int main(){
        {
            fs::pack<std::ifstream> p;
            p.open("test.cpp");
            p.readHeader();
        }
       /* {
            fs::pack<std::ofstream> p2;
            p2.open("test.cpp");
            p2.writeHeader();
        } */
        return 0;
    }
    compile est s'exécute parfaitement de mon coté.

    Mais je te rappelle le problème que j'évoquais dans ma première intervention: il n'y a rien qui nous indique, au niveau de pack, que c'est une classe qui n'est destinée qu'à la lecture!!!

    Si tu essayes de dé commenter void writeHeader() et la partie de main qui s'y rattache, tu auras une erreur de compilation parce que std::ifstream ne dispose pas plus de l'opérateur << que std::ofstream ne dispose de l'opérateur >> (et il en va, à mon sens, de meme pour les équivalents boost que tu semble utiliser ).
    A moins que fs::path ne soit qu'un typedef de std::string

    EDIT: j'ai viré pas mal de truc de ton code, uniquement pour me permettre d'avoir un code minimum compilable et ne pas dépendre d'éléments dont je ne dispose pas de mon coté
    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

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

Discussions similaires

  1. Problème avec les operators overloaded
    Par Kimy_Ire dans le forum C++
    Réponses: 5
    Dernier message: 26/11/2011, 20h14
  2. [Dev-Pascal] Error: Operator is not overloaded
    Par lasconi dans le forum Autres IDE
    Réponses: 7
    Dernier message: 29/03/2010, 20h30
  3. [Free Pascal] Operator overloaded sur un modulo
    Par mixka13 dans le forum Free Pascal
    Réponses: 3
    Dernier message: 24/01/2009, 15h07
  4. Réponses: 21
    Dernier message: 06/05/2007, 11h49
  5. Réponses: 2
    Dernier message: 15/11/2005, 10h59

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