Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 14 sur 14
  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut Tuple et machine état

    Bonjour à vous

    Je viens de penser à mettre en forme une espèce de machine état.
    Pour cela j'utilise une classe template de base : une sorte de cellule de base pour la machine état :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    template <typename T>
    class CellStateMachine
    {
        public:
            CellStateMachine(T param, boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions = boost::shared_ptr<std::list<boost::function<void (T)> > >());
            CellStateMachine(const CellStateMachine<T> &cpy);
     
            void setParam(T param);
            T getParam() const;
     
            void setListFunctionToCall(boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions);
            const boost::shared_ptr<std::list<boost::function<void (T)> > > getListFunctionsToCall() const;
     
        private:
            typedef boost::function<void (T)> func;
            T m_param;
            boost::shared_ptr<std::list<boost::function<void (T)> > > m_functionsToCall;
    };
    Ensuite je regroupe ces cellules dans un tuple :
    Code :
    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
     
    template <unsigned int Count, typename ... Args>
    class SuperCellStateMachine
    {};
     
    template <typename Head>
    class SuperCellStateMachine<0,Head>
    {
        public:
            SuperCellStateMachine(boost::shared_ptr<CellStateMachine<Head> > &cell) :
                m_cell(cell)
            {}
     
            boost::shared_ptr<CellStateMachine<Head> > m_cell;
    };
     
    template <unsigned int Count, typename Head, typename ... Args>
    class SuperCellStateMachine<Count,Head,Args...>
    {
        public:
            SuperCellStateMachine(boost::shared_ptr<SuperCellStateMachine<Count-1,Args...> > &superCell, boost::shared_ptr<CellStateMachine<Head> > &cell) :
                m_superCell(superCell),
                m_cell(cell)
            {}
     
            boost::shared_ptr<SuperCellStateMachine<Count-1,Args...> > m_superCell;
            boost::shared_ptr<CellStateMachine<Head> > m_cell;
    };
    Le problème est que je dois arriver à obtenir facilement chaque élément du tuple sans perte de temps excessive. En plus, vu la manière dont j'ai codé ça, je me suis rendu compte que ce n'était pas très pratique vu qu'il faut à chaque fois créer un pointeur sur une cellule, puis un pointeur sur une supercellule en utilisant le pointeur précédent, et continuer ainsi, en escalier, avec toujours plus de pointeurs et de template dans les supercellules créées.

    J'ai donc 2 questions : comment avec une structure similaire parvenir à accéder à chaque élément du tuple de manière rapide à la manière d'un get<N> de boost::tuple et comment optimiser ce que j'ai fait ou le remodeler de manière à disposer de quelque chose de simple à initialiser et à utiliser ?

  2. #2
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 737
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 737
    Points : 17 217
    Points
    17 217

    Par défaut

    Salut,

    Pourquoi se faire du mal inutilement...

    As tu jeté un oeil à boost, il y a deux bibliothèques de machines à état, dont l'une bien aboutie me semble-t-il
    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 habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Merci du tuyau je vais voir cela de suite

    Edit : Oui ça m'a l'air d'être ça, enfin il faudra déjà que je comprenne comment ça fonctionne vu le nombre de chose qu'il semble être possible de faire. Surtout que le tutoriel est en anglais et que sur un "sujet" assez compliqué c'est jamais trop facile quand on a pas l'habitude ^^

  4. #4
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Quelqu'un pourrait-il m'expliquer pourquoi lorsque je déclare (toujours à partir du code précédent) :
    Code :
    1
    2
    3
    CellStateMachine<float>* c1 = new CellStateMachine<float>(4.236);
    boost::shared_ptr<CellStateMachine<float> > b1(c1);
        SuperCellStateMachine<0,float>* s1 = new SuperCellStateMachine<0,float>(b1);
    J'ai ce message d'erreur :
    Code :
    error: use of deleted function 'boost::shared_ptr<CellStateMachine<float> >::shared_ptr(const boost::shared_ptr<CellStateMachine<float> >&)'

  5. #5
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 320
    Points : 2 913
    Points
    2 913

    Par défaut

    Bonsoir,

    Ça compile chez moi (on a pas les implémentation de tout les constructeurs, donc je les ai laissé vides).

    Tu pourrais donner un code complet minimal qui donne le même message ? (ie tu prends ton projet, tu le copies, tu enlèves tout ce qui sert à rien, tu mets tout dans un seul fichier, et tu copies le contenu sur le forum) Ça permettra de te donner une réponse vraiment appropriée.

    Par contre, pourquoi utiliser la syntaxe C++11 mais boost pour les shared_ptr/function ? En général si le compilateur supporte les variadics, la bibliothèque standard associée aura shared_ptr/function dans std.

    Si ta structure est similaire à un tuple, pourquoi ne pas utiliser un tuple justement (std::tuple) ?
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Oui je posterai bientôt un exemple complet de code.

    Pour ce qui est du tuple je ne peux pas utiliser la classe tuple de boost (ou de std) puisque justement je ne veux pas avoir un tuple contenant des types divers mais un tuple contenant des CellStateMachine de type divers donc il faudrait découper le template variadic au dessus d'une SuperCellStateMachine au niveau de chacun des paramètres et ça la classe tuple de boost ne le fait pas (ou alors dîtes moi comment faire en l'utilisant).


    Edit : Voici le code :

    main.cpp :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    #include "supercellstatemachine.hpp"
     
    int main()
    {   
    CellStateMachine<float>* c1 = new CellStateMachine<float>(4.236);
        CellStateMachine<std::vector<int> >* c2 = new  CellStateMachine<std::vector<int> >(std::vector<int>({0,4,5,8,9,6,3}));
        CellStateMachine<int> c3(4);
     
        boost::shared_ptr<CellStateMachine<float> > b1(c1);
        SuperCellStateMachine<0,float>* s1 = new SuperCellStateMachine<0,float>(b1);
        boost::shared_ptr<CellStateMachine<std::vector<int> > > b2(c2);
        boost::shared_ptr<SuperCellStateMachine<0,float> > bs1(s1);
        SuperCellStateMachine<1,std::vector<int>,float> s2(bs1,b2);
     
        return 0;
    }
    supercellstatemachine.hpp :
    Code :
    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
    #ifndef SUPERCELLMACHINE_HPP_INCLUDED
    #define SUPERCELLMACHINE_HPP_INCLUDED
     
     
    #include "cellstatemachine.hpp"
     
     
    template <unsigned int Count, typename ... Args>
    class SuperCellStateMachine
    {};
     
    template <typename Head>
    class SuperCellStateMachine<0,Head>
    {
        public:
            SuperCellStateMachine(boost::shared_ptr<CellStateMachine<Head> > &cell) :
                m_cell(cell)
            {}
     
            boost::shared_ptr<CellStateMachine<Head> > m_cell;
    };
     
    template <unsigned int Count, typename Head, typename ... Args>
    class SuperCellStateMachine<Count,Head,Args...>
    {
        public:
            SuperCellStateMachine(boost::shared_ptr<SuperCellStateMachine<Count-1,Args...> > &superCell, boost::shared_ptr<CellStateMachine<Head> > &cell) :
                m_superCell(superCell),
                m_cell(cell)
            {}
     
            boost::shared_ptr<SuperCellStateMachine<Count-1,Args...> > m_superCell;
            boost::shared_ptr<CellStateMachine<Head> > m_cell;
    };
     
     
    #endif
    cellstatemachine.hpp :

    Code :
    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
    #ifndef CELLSTATEMACHINE_HPP_INCLUDED
    #define CELLSTATEMACHINE_HPP_INCLUDED
     
     
    #include <list>
    #include <boost/function.hpp>
    #include <boost/shared_ptr.hpp>
     
     
    template <typename T>
    class CellStateMachine
    {
        public:
            CellStateMachine(T param, boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions = boost::shared_ptr<std::list<boost::function<void (T)> > >());
            CellStateMachine(const CellStateMachine<T> &cpy);
     
            void setParam(T param);
            T getParam() const;
     
            void setListFunctionToCall(boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions);
            const boost::shared_ptr<std::list<boost::function<void (T)> > > getListFunctionsToCall() const;
     
        private:
            typedef boost::function<void (T)> func;
            T m_param;
            boost::shared_ptr<std::list<boost::function<void (T)> > > m_functionsToCall;
    };
     
    template <typename T>
    CellStateMachine<T>::CellStateMachine(T param, boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions) :
            m_param(param)
    {
        if(listFunctions)
            m_functionsToCall = listFunctions;
    }
     
    template <typename T>
    CellStateMachine<T>::CellStateMachine(const CellStateMachine<T> &cpy) :
            m_param(cpy.getParam()),
            m_functionsToCall(cpy.getListFunctionsToCall())
    {}
     
    template <typename T>
    void CellStateMachine<T>::setParam(T param)
    {
        m_param = param;
        for(typename std::list<func>::iterator it = m_functionsToCall.begin(); it!=m_functionsToCall.end(); it++)
            if(*it)
                (*it)(m_param);
    }
     
    template <typename T>
    T CellStateMachine<T>::getParam() const
    {
        return m_param;
    }
     
    template <typename T>
    void CellStateMachine<T>::setListFunctionToCall(boost::shared_ptr<std::list<boost::function<void (T)> > > listFunctions)
    {
        if(listFunctions)
            m_functionsToCall = listFunctions;
    }
     
    template <typename T>
    const boost::shared_ptr<std::list<boost::function<void (T)> > > CellStateMachine<T>::getListFunctionsToCall() const
    {
        return m_functionsToCall;
    }
     
    #endif

  7. #7
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 320
    Points : 2 913
    Points
    2 913

    Par défaut

    Je vais regarder ton code, mais en attendant, tu as essayé des syntaxes comme :
    Code :
    1
    2
     
    std::tuple<SuperCellStateMachine<Arg>...>
    ?

    Edit: J'ai regardé ton code. Quel sont ton compilateur et ta version de boost ? Avec gcc 4.7 et boost 1.52 ton code compile sans problèmes (je n'ai fait que copier/coller et n'ai pas vérifier si il fonctionne comme attendu par contre).
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  8. #8
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 737
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 737
    Points : 17 217
    Points
    17 217

    Par défaut

    Citation Envoyé par Lintel-oo Voir le message
    Pour ce qui est du tuple je ne peux pas utiliser la classe tuple de boost (ou de std) puisque justement je ne veux pas avoir un tuple contenant des types divers mais un tuple contenant des CellStateMachine de type divers
    Je ne comprend pas très bien, là...

    La notion de tuple, c'est comme la notion de file, de pile ou de list: c'est une notion tout à fait générique qui va contenir ce que tu veux que cela contienne

    Un tuple n'est en fait jamais qu'un ensemble de données qui permettent de représenter "quelque chose"

    Partant de là, tu peux très bien considérer l'idée de regrouper différents états dans un tuple pour qu'ils représentent les différents états d'une machine à états, où serait le problème

    Au pire, tu délègues à une classe ou à une fonction le fait de vérifier que chaque élément de ton modèle variadique est bien un pointeur vers un objet dont le type est dérivé de CellStateMachine; et, avec le static_assert, tu peux avoir des messages d'erreurs particulièrement intéressants ... Par exemple :
    Code :
    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
    #include <type_traits>
    #include <tuple>
    struct CellStateMachine
    {
     
    };
    struct MySpecificState : CellStateMachine
    {
     
    };
    struct OtherSpecificState : CellStateMachine
    {
     
    };
    /* to break recursion on last template parameter */
    template <typename T>
        void checkIfDerivedFromCellStateMachine(T t)
        {
            static_assert( std::is_base_of<CellStateMachine, T>::value,
                           "You should use only CellStateMachine derived types");
        }
    template <typename T, typename ... Args>
        void checkIfDerivedFromCellStateMachine(T t, Args... args)
        {
            static_assert( std::is_base_of<CellStateMachine, T>::value,
                           "You should use only CellStateMachine derived types");
                checkIfDerivedFromCellStateMachine<Args...>(args...);
        }
    template< typename ... Args>
    struct StateMachine
    {
        typedef std::tuple<Args...> states_t;
        states_t states;
        StateMachine(Args... args):states(std::make_tuple(args...))
        {
            checkIfDerivedFromCellStateMachine(args...);
        }
    };
    struct NotAState
    {
     
    };
     
    int main()
    {
        MySpecificState first;
        OtherSpecificState second;
        StateMachine<MySpecificState,OtherSpecificState> sm(first, second);
        NotAState nas;
        StateMachine<MySpecificState,OtherSpecificState, NotAState> error(first, second, nas);
    }
    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

  9. #9
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Je vais regarder ton code, mais en attendant, tu as essayé des syntaxes comme :

    Code :
    std::tuple<SuperCellStateMachine<Arg>...>
    Non pas encore je regarderai cela demain.

    En ce qui concerne ma version de gcc, il s'agit de la dernière (4.7) et pour celle de boost je ne sais pas exactement, juste qu'elle est assez récente, mais je ne sais pas si c'est la dernière !

    @koala01 :
    En fait je pense m'être mal exprimé, enfin j'ai mal compris le concept exact de machine état. En effet, ce que je voudrais parvenir à faire est un ensemble de classe permettant de greffer des modules d'analyse d’événements et de temps agissant sur les cellules de la "machine état", cellules utilisées notamment à des fins graphiques, par exemple la position d'un sprite à l'écran, la couleur d'un pixel ...

    La liste de pointeurs de fonctions dans la cellule étant bien sur utilisée pour modifier dans les classes concernées les attributs notamment graphiques lors du changement de valeur dans la cellule.

  10. #10
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Après test je dispose de la version 1.46.1 de boost.

    Edit : Je viens d'installer la dernière version et maintenant ça compile (même si je ne comprends toujours pas pourquoi ça ne compilait pas avant ^^)

  11. #11
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 320
    Points : 2 913
    Points
    2 913

    Par défaut

    As-tu essayé :
    Code :
    std::tuple<SuperCellStateMachine<Arg>...>
    Parce que là t'es quand même en train de réinventer la roue ... Si le langage dispose maintenenant des templates variadiques, c'est pas pour continuer à faire des type lists à la main.

    Et sinon :
    Par contre, pourquoi utiliser la syntaxe C++11 mais boost pour les shared_ptr/function ?
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  12. #12
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Oui je suis en train de voir ça.

    Sinon le std::shared_ptr est "le même" que le boost::shared_ptr ? (c'est juste pour savoir)

    Edit :
    std::tuple<SuperCellStateMachine<Arg>...>
    Ca compile (je vais voir si ça fonctionne correctement tout à l'heure).


    J'aimerais également savoir ce que vous pensiez sur l'avantage de la machine à état par rapport à ce que je suis en train de faire, et également si il existait un concept qu'y s'y rapproche plus.

  13. #13
    Invité régulier
    Inscrit en
    mai 2011
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : mai 2011
    Messages : 5
    Points : 8
    Points
    8

    Par défaut

    std::shared_ptr est inspiré de boost::shared_ptr donc c'est à peut de choses près les mêmes.

    D'ailleurs la bonne façon d'allouer un shared ptr c'est:
    Code :
    1
    2
     
    std::shared_ptr<T> ptr = std::make_shared<T>(arguments du constructeur);

  14. #14
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    avril 2011
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : avril 2011
    Messages : 249
    Points : 125
    Points
    125

    Par défaut

    Merci pour ta réponse.

    Un problème de conception maintenant :
    Est-il envisageable de respecter un design objet en établissant une instance statique d'une sorte de "mémoire centrale" composée de nombreuses données membres (spécifiques et spécifiée pour chaque nouveau programme utilisant la classe concernée) pouvant être modifiées depuis n'importe quel endroit du programme et utilisées de la même manière.

    Je me demandais si cela pouvait être viable car cela constituerait en quelque sorte une seconde "mémoire" accessible et modifiable partout. Je trouvais cela utile par exemple ne serait-ce que pour un jeu.
    En effet, pourquoi vouloir à tout prix diversifier le code source en une multitude insensée de classes peu réutilisables alors qu'il serait possible de mettre en place un système beaucoup plus souple où la majorité des variables de jeu quelles qu'elles soient seraient centralisées et où des éléments d'analyse et de modification très modulables seraient "greffés" au programme ?

    En espérant n'avoir pas été trop confus

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •