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 :

Solution plus élégante possible ou pas ?


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Solution plus élégante possible ou pas ?
    Salut, alors je vais essayé d'expliqué ma solution.

    J'écris des données de tout type d'objets dans un fichier à l'aide de quelque classes et une macro qui associe un type de base à ses types dérivé en déclarant une structure qui hérite d'un sérialiseur qui contient un tuple avec un pointeur sur l'objet dérivé et un pointeur sur l'objet de base.

    Cette macro ajoute donc la déclaration de cette structure dans la classe de base ainsi qu'un objet de cette structure en variable membre à la classe de base. (j'appelle cet objet, la clé)

    Le sérialiseur contient plusieurs fonctions utiles :

    -Une pour rechercher le type réel de l'objet et appeler la fonction de sérialisation sur le type réel de l'objet en faisant une recherche à l'aide de typeid dans le tuple.
    -Une autre pour retourner l'index du pointeur sur le type réel de l'objet dans le tuple.
    -Et enfin, une autre pour pouvoir allouer le pointeur sur l'objet de base avec le type réel de l'objet à la lecture. (Pour connaître le type réel de l'objet j'écris juste l'id du type réel de base de l'objet dans un fichier)

    Le problème est que le compilateur n'a pas l'air d'aimer cela, bref, voici une solution que j'ai mis en place et qui marche avec l'option -fpermissive :

    Voici le sérialiseur qui contient le tuple et qui contient quelque fonctions/structure utilitaire d'allocation, de recherche d'index et de type ainsi que d'appel de la fonction sur le type réel de l'objet à l'exécution.

    Code cpp : 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
    110
    111
    112
    113
    114
     
    #ifndef ODFAEG_SERIALIZATION
    #define ODFAEG_SERIALIZATION
    #include <iostream>
    #include <typeinfo>
    #include "tuple.h"
    #include <tuple>
    namespace odfaeg {
    template <int N, typename B, typename T, typename A>
    struct serializer {
        static void checkType (B* base, T tuple, A & ar) {
            if (std::get<N>(tuple) != nullptr && typeid(*base) == typeid(*std::get<N>(tuple))) {
                std::get<N>(tuple)->serialize(ar);
            }
            serializer<N-1, B, T, A>::checkType(base, tuple, ar);
        }
    };
    template <typename B, typename T, typename A>
    struct serializer <0, B, T, A> {
        static void checkType (B* base, T tuple, A & ar) {
            if (std::get<0>(tuple) != nullptr && typeid(*base) == typeid(*std::get<0>(tuple))) {
                std::get<0>(tuple)->serialize(ar);
            } else if (base != nullptr) {
                base->serialize(ar);
            }
     
        }
    };
    template <int N, typename B, typename T>
    struct sallocator {
        static B* instanciate (int index, T tuple) {
            if (N == index) {
                using D = typename std::remove_pointer<typename std::tuple_element<N, T>::type>::type;
                return new D();
            }
            sallocator<N-1, B, T>::instanciate(index, tuple);
        }
    };
    template <typename B, typename T>
    struct sallocator <0, B, T> {
        static B* instanciate (int index, T tuple) {
            using D = typename std::remove_pointer<typename std::tuple_element<0, T>::type>::type;
            return new D();
        }
    };
    template <int N, typename B, typename T>
    struct sindex {
        static int getIndex (B* base, T tuple) {
            if (std::get<N>(tuple) != nullptr && typeid(*base) == typeid(*std::get<N>(tuple))) {
                return N;
            }
            sindex<N-1, B, T>::getIndex(base, tuple);
        }
    };
    template <typename B, typename T>
    struct sindex <0, B, T> {
        static int getIndex (B* base, T tuple) {
            using D = typename std::remove_pointer<typename std::tuple_element<0, T>::type>::type;
            D* derived = new D();
            if (std::get<0>(tuple) != nullptr && typeid(*base) == typeid(*std::get<0>(tuple))) {
                return 0;
            }
            return -1;
        }
    };
     
    template <class B, class... D>
    class Serializer {
        public :
        Serializer() {
            baseObject = nullptr;
        }
        Serializer(B* baseObject) : baseObject(baseObject) {
            fillTuple(derivedClasses);
        }
        void setObject(B* baseObject) {
            this->baseObject = baseObject;
            fillTuple(derivedClasses);
        }
        template<int... S>
        void fillTuple(std::tuple<D*...> types) {
            fillTuple(typename helper::gens<sizeof...(D)>::type(), types);
        }
        template<int... S>
        void fillTuple(helper::seq<S...>, std::tuple<D*...> params) {
             derivedClasses = std::forward_as_tuple(dynamic_cast<typename std::remove_reference<decltype(std::get<S>(params))>::type> (baseObject)...);
        }
        template <typename Archive>
        void serialize(Archive & ar) {
            if (std::tuple_size<decltype(derivedClasses)>::value > 0)
                serializer<std::tuple_size<decltype(derivedClasses)>::value-1, B, decltype(derivedClasses), Archive>::checkType(baseObject, derivedClasses, ar);
            else
                baseObject->serialize(ar);
        }
        virtual void onSave() {
        }
        virtual void onLoad() {
        }
        B* sallocate(int index) {
            if (std::tuple_size<decltype(derivedClasses)>::value > 0)
                return sallocator<std::tuple_size<decltype(derivedClasses)>::value-1, B, decltype(derivedClasses)>::instanciate(index, derivedClasses);
     
        }
        int getIndex() {
            if (std::tuple_size<decltype(derivedClasses)>::value > 0)
                return sindex<std::tuple_size<decltype(derivedClasses)>::value-1, B, decltype(derivedClasses)>::getIndex(baseObject, derivedClasses);
            return -1;
        }
        private :
        B* baseObject;
        std::tuple<D*...> derivedClasses;
    };
    }
    #endif // SERIALIZATION

    Si le type statique de l'objet est le même que le type dynamique de l'objet, alors je retourne -1 comme index.

    Voici le contenu de mon autre fichier qui n'est rien d'autre qu'une macro qui va inclure le tout dans le fichier.h de la classe de base pour que je puisse avoir accès à la clé dans l'archive :

    Code cpp : 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 "serialization.h"
    #ifndef SERIALIZATION_CPP
    #define SERIALIZATION_CPP
    #define REGISTER_KEY(KEY, TYPE, TYPES...)  \
    struct KEY : public  odfaeg::Serializer<TYPE, TYPES> { \
        public : \
        KEY () {} \
        void register_object (TYPE* object) { \
            setObject(object); \
        } \
        TYPE* allocate_object(int index) { \
            return sallocate(index); \
        } \
        int getTypeIndex () { \
            return odfaeg::Serializer<TYPE, TYPES>::getIndex(); \
        } \
        template <typename Archive> \
        void serialize_object (Archive & ar, int) { \
            odfaeg::Serializer<TYPE, TYPES>::serialize(ar); \
        } \
    }; \
    KEY key; \
    static TYPE* allocate (int index) { \
        static KEY aKey; \
        return aKey.allocate_object(index); \
    }
    #endif // SERIALIZATION_CPP

    Et enfin dans l'archive je n'ai plus qu'à accéder à la clé, afin d'écrire tout ça :

    Si l'objet possède un pointeur de fonction prenant une archive et un int, alors, cela veut dire que il est possible que l'objet soit polymoprhique, sinon, j'appelle directement la fonction serialize contenue dans la classe de l'objet. (J'ai deux fonction, une contenue dans la classe de l'objet et une autre contenue dans la définition de la clé), le int dans la fonction elle même ne sert donc à rien, il me sert juste à appliquer le principe de SFINAE.

    Code cpp : 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
     
    template <class O,
                  class... D,
                  class = typename std::enable_if<std::is_member_function_pointer<void(O::*)(OTextArchive&)>::value>::type,
                  class = typename std::enable_if<std::is_member_object_pointer<decltype(&O::key)>::value>::type,
                  class = typename std::enable_if<!std::is_same<O, std::string>::value>::type,
                  class = typename std::enable_if<!sizeof...(D)>::type>
    void operator() (O* object, D...) {
            std::map<unsigned long long int, unsigned long long int>::iterator it = adresses.find(reinterpret_cast<unsigned long long int>(object));
            if (it != adresses.end()) {
                buffer<<it->second<<" ";
            } else {
                int index = -1;
                std::pair<unsigned long long int, unsigned long long int> newAddress (reinterpret_cast<unsigned long long int>(object), nbSerialized);
                adresses.insert(newAddress);
                if (typeid(decltype(*object)) == typeid(*object)) {
                    std::cout<<"non polymoprhic version"<<std::endl;
                    buffer<<newAddress.second<<" ";
                    buffer<<index<<" ";
                    object->serialize(*this);
                } else {
                    std::cout<<"polymoprhic version"<<std::endl;
                    object->key.register_object(object);
                    index = object->key.getTypeIndex();
                    buffer<<newAddress.second<<" ";
                    buffer<<index<<" ";
                    object->key.serialize_object(*this, 0);
                }
                nbSerialized++;
            }
        }


    Je sauve donc l'index du type dynamique de l'objet. (-1 si le type dynamique est le même que le type statique)

    Cette solution marche extrêmement bien et me permet de définir ce que je veux sérialiser dans le fichier.h de la classe de base et même redéfinir ça dans le main si le fichier.h est contenu dans une librairie pour ne pas avoir à modifer le .h de la librairie si je rajoute des classes dérivées.

    Cependant il y a un petit problème à la lecture :

    Code cpp : 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
     
    void operator() (O** object, D...) {
     
            unsigned long long int id;
            int index;
            buffer>>id;
            buffer>>index;
            std::map<unsigned long long int, unsigned long long int>::iterator it = adresses.find(id);
            if (it != adresses.end()) {
                *object = reinterpret_cast<O*>(it->second);
            } else {
                if (index == -1) {
                     std::cout<<"non polymorphic version"<<std::endl;
                     *object = new O();
                    (*object)->serialize(*this);
                    std::pair<unsigned long long int, unsigned long long int> newAddress (id, reinterpret_cast<unsigned long long int>(object));
                    adresses.insert(newAddress);
                } else {
                    std::cout<<"polymorphic version"<<std::endl;
                    *object = O::allocate(index);
                    (*object)->key.register_object(*object);
                    (*object)->key.serialize_object(*this, 0);
                    std::pair<unsigned long long int, unsigned long long int> newAddress (id, reinterpret_cast<unsigned long long int>(object));
                    adresses.insert(newAddress);
                }
                nbDeserialized++;
            }
        }

    Que voici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ||=== Build: Debug in ODFAEG-DEMO (compiler: GNU GCC Compiler) ===|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|9|warning: "G2DEKEY" redefined [enabled by default]|
    /usr/local/include/odfaeg/Graphics/2D/entity.h|13|note: this is the location of the previous definition|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|36|warning: "/*" within comment [-Wcomment]|
    /usr/local/include/odfaeg/Core/archive.h||In instantiation of ‘void odfaeg::ITextArchive::operator()(O**, D ...) [with O = odfaeg::BoundingBox; D = {}; <template-parameter-1-3> = void; <template-parameter-1-4> = void; <template-parameter-1-5> = void; <template-parameter-1-6> = void]’:|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|65|required from here|
    /usr/local/include/odfaeg/Core/archive.h|513|error: invalid conversion from ‘odfaeg::BoundingVolume*’ to ‘odfaeg::BoundingBox*’ [-fpermissive]|
    ||=== Build failed: 1 error(s), 4 warning(s) (0 minute(s), 5 second(s)) ===|
    J'ai donc rajouté l'option -fpermissive pour que gcc me foute la paix car de toute façon il n'ira jamais dans le else si le type dynamique est diffférent du type statiqque, mais je ne sais pas si c'est la meilleur solution.

  2. #2
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    J'ai rien compris

    Mais une simple surcharge de l'opérateur de flux << et >> ne suffit pas? Si c'est juste de la sérialisation tu te complique vraiment la vie.

    Sinon un manière élégante et plus complexe que les flux est de créer un Custom RTTI, je te laisse cherche sur Google
    Homer J. Simpson


  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Pour commencer, chaque warning devrait être corrigé...

    error: invalid conversion from ‘odfaeg::BoundingVolume*’ to ‘odfaeg::BoundingBox*’
    il te hurle (error) qu'un odfaeg::BoundingVolume* n'est pas un ‘odfaeg::BoundingBox*.
    C'est à dire qu'a priori, BoundingVolume n'hérite pas de BoundingBox
    C'est d'ailleurs très probablement le contraire.

    La solution est un down cast, qui je crois s'écrit avec std::dynamic_cast.
    Et c'est toujours une erreur.

    Le code utilisateur de ta sérialisation devrait pouvoir agir de la même manière qu'avec std::cout.
    Je m'explique:

    Si je veux écrire une classe Bidule sur cout, j'ai le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Bidule{}
     
    std::ostream& operator<<(std::ostream & os, Bidule const& that) {//avec un warning sur that unused, je sais...
        return os <<"un bidule quelconque";
    }
    Je suis obligé d'écrire une fonction supplémentaire ayant un nom et une signature précis.

    cela sous entends qu'on a dans <iostream> les choses suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class ostream{
    //...
    ostream& operator<<(int);
    ostream& operator<<(char);
    ostream& operator<<(double);
    ostream& operator<<(const void*);
    };
    (voir une spec)

    Tu pourrais faire pareil:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    namespace serializer{
    classe Serializer{
    Serializer& operator<<(int);
    Serializer& operator<<(char);
    Serializer& operator<<(double);
    Serializer& operator<<(const void*);
    };
    }
     
    namespace lib {
    class BoundingVolume{...};
    Serializer& operator<<(Serializer&, BoundingVolume const&);
    }
    et t'attendre à ce que ton utilisateur écrive ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class Bidule : public BoundingVolume{...};
    Serializer& operator<<(Serializer&, Bidule const&);
     
    int main () {
        serializer::Serializer output;
        lib::BoundingVolume *box = new lib::BoundingBox(), *bidule = new Bidule(...);
        output<<*box << *bidule;
        return 0;
    }
    J'ai volontairement pris operator<<, parce qu'il y a une souplesse avantageuse: il peut être défini comme fonction membre ou comme fonction libre.
    Les fonctions membres pour les primitifs, car Serializer est le seul à savoir qu'en faire.
    Les fonctions libres pour les autres types, ce qui permet de les faire définir par l'utilisateur.


    Ce qu'il nous manque pour t'aider enfin, c'est une spécification du format d'archivage.
    Ca ressemble à la version fichier d'un vector< pair<string type, string serialform> >
    auquel cas, il te suffit de définir des fonctions qui produit les pair<string type, string serialform> correspondant à chaque type.

    Si je comprends bien, ton problème se résume à avoir une classe permettant de stocker des pointeurs de fonction de traduction.
    Quelque chose qui réponde au besoin logique suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    template <class C extends serializable> Archive& Archive::operator<<(C const&);
    il existe type_info, j'imagine que ceci est presque possible (je n'ai pas vraiment essayé)
    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
    class Archive {
    public:
    typedef Archive& (*serialize_t)(Archive&, serializable const&);
    private:
    map<type_info, serialize_t> helpers;
     
    public:
        void register(type_info const& type, serialize_t helper) {
            if ( ! /*validation de type*/ ) throw std::illegal_argument();
            helpers.emplace(type, helper);
        }
        Archive& operator<<(serializable const& that) {
            return helpers[/*je ne sais plus obtenir le type_info de that*/](*this, that);
        }
    };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Membre régulier
    Homme Profil pro
    Ingénieur
    Inscrit en
    Octobre 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Transports

    Informations forums :
    Inscription : Octobre 2006
    Messages : 48
    Points : 97
    Points
    97
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Salut, alors je vais essayé d'expliqué ma solution.

    J'écris des données de tout type d'objets dans un fichier à l'aide de quelque classes et une macro qui associe un type de base à ses types dérivé en déclarant une structure qui hérite d'un sérialiseur qui contient un tuple avec un pointeur sur l'objet dérivé et un pointeur sur l'objet de base.
    FAIL. Pourquoi faire simple quand on peut faire compliqué

  5. #5
    Invité
    Invité(e)
    Par défaut
    Salut.

    Finalement j'ai réussi à avoir un code qui compile, sans devoir rajouté d'option, je m'étais, en effet trompé et il fallait que je spécifie une surcharge de fonction supplémentaire.

    Je ne veux en effet ne pas passer par un système de "custom RTTI" qui compliquerai les choses.

    Je veux avoir un truc simple.

    Le problème des opérateurs << et >>, c'est qu'il ne peuvent prendre qu'un (ou deux si ce n'est pas une fonction membres) arguments supplémentaire, je ne peux pas utiliser SFINAE donc.

  6. #6
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Le problème des opérateurs << et >>, c'est qu'il ne peuvent prendre qu'un (ou deux si ce n'est pas une fonction membres) arguments supplémentaire, je ne peux pas utiliser SFINAE donc.
    Bas tu créer juste une class serialize, tu ajoutes des fonctions read write et tu les surcharges dans chaque classe enfant. je comprends pas pourquoi tu as fais si compliqué
    Homer J. Simpson


  7. #7
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2014
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2014
    Messages : 345
    Points : 1 211
    Points
    1 211
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Je veux avoir un truc simple.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Salut.

    Je ne peux malheureusement pas surcharger une fonction template. :/

    Et puis j'ai voulu partir sur un système similaire à celui de boost pour des raisons de compatibilité.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Ce code :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <class C extends serializable> Archive& Archive::operator<<(C const&);

    Ne fonctionne que en java non ?

    Avec typeinfo je crains que cela ne soit pas possible, il faut appeler l'operateur<< sur le bon type, donc, je dois doit pouvoir stocker le bon type en compilation et le rechercher à l'exécution pour appeler la fonction de la bonne classe.

    Je trouve pas ças très pratique de devoir redéfinir l'operator<< pour tout les types primitifs.

  10. #10
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Je ne peux malheureusement pas surcharger une fonction template. :/
    Mais tu peux ne pas faire de template ^^
    Homer J. Simpson


  11. #11
    Invité
    Invité(e)
    Par défaut
    Mmm, ça ne va pas être très pratique de ne pas faire de template (à vrai dire je ne suis pas très convaincu par cette possibilité), surtout que j'ai pleins de type différents à sérialiser, et en plus, il peut y avoir aussi plusieurs type d'archives différentes.

  12. #12
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Ce code :
    template <class C extends serializable> Archive& Archive::operator<<(C const&);Ne fonctionne que en java non ?
    c'est pourquoi que je parlais de besoin logique.

    Citation Envoyé par Lolilolight Voir le message
    Avec typeinfo je crains que cela ne soit pas possible, il faut appeler l'operateur<< sur le bon type, donc, je dois doit pouvoir stocker le bon type en compilation et le rechercher à l'exécution pour appeler la fonction de la bonne classe.

    Je trouve pas ças très pratique de devoir redéfinir l'operator<< pour tout les types primitifs.
    L'écriture d'une classe doit être pratique pour son utilisateur, pas son concepteur.
    Et les types primitifs sont peu nombreux, 13 si j'en crois ostream.

    En plus, tu as l'avantage de pouvoir compter sur les conversions.
    Tu peux te contenter dans un premier temps de const char*, void*, bool, char, long, et double


    C'est l'intérêt de ma suggestion.
    Une classe n'est toujours qu'un type précis et une suite de variables de types primitifs, regroupées potentiellement en sous-structures.
    Quelque soit l'archive elle doit aisément savoir sauvegarder les types primitifs, et les chaines de caractères.

    Il te reste à fournir aux créateurs de classes de dire dans quel ordre sérialiser leurs membres.

    Il existe des bibliothèques qui utilise propose la création de zip, de sockets, etc via des classes héritant de ostream.
    Je ne vois pas ce qui t’empêche d'en faire autant.

    Tu ne peux pas espérer magiquement sauvegarder une classe que tu ne connais pas sans demander à son fournisseur un minimum de travail.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  13. #13
    Invité
    Invité(e)
    Par défaut
    Ok, béh je pense que je vais essayer ça hein.

    Donc je n'ai qu'à appelé l'operateur<< sur l'archive qui va prendre, un objet. (ou un type primitif donc)

    Et surcharger les opérateurs << et >> dans les classes dérivée si il y en a, c'est ça ?

    Alors je devrai en plus faire hériter chaque classe d'une classe de base commune que je vais passer à l'opérateur de flux.

    Mmm, je ne sais pas si c'est très pratique pour l'utilisateur de faire cela, faire hériter chaque classe de serializable.

    Ici il ne fait que de redéfinir une méthode et utiliser une macro dans la classe de base, donc, il ne faut modifier que la classe de base et redéfinir la méthode serialize dans chaque classes, avec ton système, il faudrait faire hériter toutes les classe du serializer, je préfère quand même lorsque l'utilisateur ne doit pas faire d'héritage, ne penses tu pas que ça serait plus simple ?

    Maintenant il y a aussi un inconvénient avec la macro ce sont les problèmes liés aux forwards déclaration. (Le serializer a besoin de la définition complète de la classe dérivée hors il ne la connaît pas.)

    Mais ce qui me surprend c'est que avec la classe BoundingBox ça compile sans que le serializer aie besoin de la définition complète de la classe, avec la classe Tile, ça me fou une erreur de compilation.

    J'ai du loupé quelque chose mais je ne vois pas quoi...

    Il me semble que j'avais déjà essayé ta solution avec les operateurs << que je redéfinissais sur les archives, mais, ça ne marchera pas, l'opérateur doit retourner un objet de type ostream. (Et pas un objet de type Archive&)

  14. #14
    Invité
    Invité(e)
    Par défaut
    Bon je pense que je vais faire comme tu dis finalement, je ne vois pas d'autres solution, j'en ai marre de ses erreurs de compilations due aux forward déclarations et ça devient in maintenable.

    J'espère simplement que ta solution va fonctionner.

  15. #15
    Invité
    Invité(e)
    Par défaut
    Ha oui, il y a aussi un autre inconvénient, je dois redéfinir les opérateur << et >> donc deux opérateur au lieu d'un seul.

  16. #16
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    C'est aussi vrai avec cin cout...
    La magie n'existe pas, on a rien sans rien.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  17. #17
    Invité
    Invité(e)
    Par défaut
    Ok bah je vais essayer de faire cela.

    Avec l'opérateur& peut être que, il y a moyen de faire qu'un seul opérateur.

    Je vais voir...

  18. #18
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Oui, mais non, parce que chaque classe se sérialize différemment.

    Et tu n'as pas des douzaines de classes différentes. Si?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  19. #19
    Invité
    Invité(e)
    Par défaut
    Ouais par contre, je ne vois pas comment faire quelque chose comme ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <typename D extends B> operator<<(std::ostream& out, Serializable &o)

    Peut être en faisant une classe de base nommée Archive et la faire dérivé.

    Ma solution utilisant une classe de trait ne fonctionne pas, pourtant, je ne pense pas qu'il aie besoin du type complet de la classe ici, si ?

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct sallocator {
        static B* instanciate (int index, T tuple) {
            if (N == index) {
                using D = typename std::remove_pointer<typename std::tuple_element<N, T>::type>::type;
                return new D();
            }
            sallocator<N-1, B, T>::instanciate(index, tuple);
        }
    };

    Ou alors peut être pour connaître la taille de la classe.
    Pareil pour le dynamic cast il a besoin de connaître la définition complète de la classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    /home/laurent/Développement/Projets-c++/ODFAEG/src/odfaeg/Graphics/2D/../../../../include/odfaeg/Graphics/2D/../../Math/../Core/serialization.h|56|error: invalid use of incomplete type ‘using D = std::__remove_pointer_helper<odfaeg::g2d::Tile*, odfaeg::g2d::Tile*>::type {aka class odfaeg::g2d::Tile}’|
    En fait ce que je voudrais faire c'est allouer le pointeur avec le type dynamique de l'objet (lors de la lecture), mais je ne vois pas du tout comment faire, en plus, j'ai un problème, c'est que je dois connaître la définition complète de la classe de l'objet pour pouvoir l'allouer.

    Donc, je ne peut pas stocker un wrapper dans la classe de base de l'objet, car dans la classe de base je n'ai pas la définition complète des classes dérivée, et, je ne vois pas du tout comment je pourrai réglé se problème. :/

    Si quelqu'un à une solution je suis preneur, j'ai essayé d'inclure les .h des classes dérivées dans le wrapper, mais ça ne marche pas, j'ai alors une autre erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    /home/laurent/Développement/Projets-c++/ODFAEG/src/odfaeg/Core/../../../include/odfaeg/Core/../Graphics/../Physics/../Core/../Graphics/2D/../transformable.h|17|error: ‘BoundingBox’ does not name a type|
    A cause de la forward déclaration ici :

    Code cpp : 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
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
     
    #ifndef ODFAEG_ENTITY_2D_HPP
    #define ODFAEG_ENTITY_2D_HPP
    #include "../transformable.h"
    #include "../drawable.h"
    #include "../../Physics/boundingVolume.h"
    #include "../../Core/state.h"
    #include "../../Core/stateExecutor.h"
    #include "../renderTarget.h"
    #include "../face.h"
    #include "../../Math/computer.h"
    #include <vector>
    namespace odfaeg {
        namespace g2d {
        class Tile;
    /**Class entity by Laurent Duroisin (all right reserved)
     * this abstract class is the base of all drawable and transformable's entities of the framework.
     * this class inherits from the transformable and the drawable class.
     * entities are components, then, they can have parent entities and children entities.
     * (CF : Design pattern component)
     */
    class ODFAEG_GRAPHICS_API Entity : public Transformable, public Drawable {
        public :
            /** position : the position of the top left corner of the entity
             * size : the size of the entity
             * origin : the origin of the entity's position wich is local to the entity's position.
             * zOrder : the layer's position of the entity
             * type : the type of the entity. (the type can be anything (model, floor, light, shadow, etc...))
             * the type should describe the kind of the entity.
             * parent : the parent of the entity, the value is null if the entity doesn't have a parent.
             */
            Entity (Vec3f position, Vec3f size, Vec3f origin, std::string type, Entity* parent = nullptr);
            //Get the number of entities created with the application.
            static int getNbEntities ();
            //Get teh type of the entity.
            std::string getType() const;
            //Get the type's id of the entity.
            int getTypeInt ();
            //Get the type corresponding to the given id.
            static std::string getTypeOfInt (int type);
            //Get the id corresponding to the given type.
            static int getIntOfType (std::string type);
            //Get the radius of the entity.
            int getRadius ();
            std::string getRootType();
            //Init the map who is a correspondance between a type of an entity and the id of it's type.
            static std::map<int, std::string>* initTypes () {
                if (types == nullptr) {
                    static std::map<int, std::string> *t = new std::map<int, std::string> ();
                    return t;
                }
                return types;
            }
            //Return the id of the entity.
            int& getId();
            //Set an id to the entity.
            void setId (int id);
            //This method have to be redifinied to determine when two entity's are equals.
            //This can avoid to have two equqls entity's at the same place.
            virtual bool operator== (Entity& other) = 0;
            void draw (RenderTarget &target, RenderStates states);
            virtual void onDraw(RenderTarget &target, RenderStates states) const {}
            virtual void onMove(Vec3f &t);
            virtual void onScale(Vec3f &s);
            virtual void onRotate(float angle);
            //Return the parent of the entity.
            Entity* getParent() const;
            //Set the parent's entity of the entity.
            void setParent (Entity *parent);
            //Add a children to the entity.
            void addChild (Entity *child);
            //Remove a children to the entity.
            void removeChild (Entity *child);
            //Return the children of the entities.
            std::vector<Entity*> getChildren() const;
     
            //Return the number of entity's children.
            unsigned int getNbChildren ();
            //Determine if the entity is animated.
            virtual bool isAnimated() const = 0;
            //Determine if the entity have a shadow.
            virtual bool isModel() const = 0;
            virtual bool selectable() const = 0;
            virtual bool isLight() const = 0;
            virtual bool isShadow() const = 0;
            virtual bool isLeaf() const = 0;
            //Set the type of the entity.
            void setType (std::string type);
            //Destructor.
            template <typename T> bool addAttribute (std::string name, T value) {
                return entityState.addParameter(name, value);
            }
            template <typename T> bool addAttribute (std::string name, T* value) {
                return entityState.addParameter(name, value);
            }
            const StateParameter& getAttribute (const std::string name) throw (odfaeg::Erreur) {
                   return entityState.getParameter(name);
            }
            template <typename T> void changeAttribute (const std::string name, T value) {
               entityState.changeParameter(name, value);
            }
            bool removeAttribute (std::string name) {
                entityState.removeParameter(name);
            }
            bool interact(StateExecutor *se) {
                entityState.setExecutor(se);
                return entityState.doActionState();
            }
            bool uninteract (StateExecutor *se) {
                entityState.setExecutor(se);
                return entityState.undoActionState();
            }
            void setCollisionVolume (BoundingVolume* volume) {
                this->collisionVolume = volume;
            }
            BoundingVolume* getCollisionVolume () const {
                return collisionVolume;
            }
            void addFace(Face* face);
            std::vector<Face*> getFaces() const;
            template <typename Archive>
            void serialize(Archive & ar) {
                Transformable::serialize(ar);
                ar(id);
                ar(faces);
                ar(type.first);
                ar(type.second);
                ar(children);
                ar(parent);
                ar(children);
                ar(collisionVolume);
            }
            void onLoad() {
                types = initTypes();
                int iType = getIntOfType(getType());
                if (iType == -1) {
                    type = std::pair<int, std::string> (nbEntitiesTypes, getType());
                    types->insert(type);
                    nbEntitiesTypes++;
                }
                nbEntities++;
            }
            virtual ~Entity();
        protected :
            std::vector<Face*> faces;
            static std::map<int, std::string> *types;
            std::pair<int, std::string> type;
            std::vector<Entity*> children;
            Entity* parent;
            int id;
            static int nbEntities, nbEntitiesTypes;
            State entityState;
            BoundingVolume *collisionVolume;
            REGISTER_KEY(G2DENTITY, Entity, Tile)
    };
    }
    }
    #endif

    Bref j'arrive pas à trouver une solution pour passer outre de ses problèmes de forward déclaration.

  20. #20
    Invité
    Invité(e)
    Par défaut
    Je pense que j'ai trouvé une autre solution, je vais essayer passer les clés dans les classes OTextArchive et ITextArchive comme le fait boost et non plus dans la classe de base de l'objet ainsi fini les problèmes il suffira que j'inclus les classes dérivée avant d'inclure l'archive mais actuellement je ne vois pas de trop comment exporter les clés dans les archives.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Obtenir un ensemble de solutions les plus différentes possibles
    Par karas.uchiwa dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 30/03/2010, 12h28
  2. Réponses: 10
    Dernier message: 12/01/2006, 21h22
  3. [VBA]possible ou pas ? creer une image jpg a partir 7 jpg
    Par sakuraba dans le forum Général VBA
    Réponses: 5
    Dernier message: 03/01/2006, 10h45
  4. [Info]Solution CMS (Si possible JSP/Servlets)
    Par lolo le belge dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 16/12/2005, 22h55
  5. Permuter des valeurs, le plus rapidement possible?
    Par danje dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 27/09/2005, 21h51

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