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 :

SFINAE. (je ne comprend pas)


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut SFINAE. (je ne comprend pas)
    Salut!

    J'arrive enfin au bout de mes peines avec mon système de sérialisation. (quoi que..., pas encore tout à fait!)

    Je n'ai trouvé d'autres solutions que d'appeler 4 fonction template différente ce qui est beaucoup (je sais) et je ne sais même pas si cela est possible avec SFINAE, je pense que c'est possible mais j'ai du manqué de compréhension.

    La 1ère fonction écrit des types fondamentaux en les insérant directement dans le flux, chacun sont séparé par un espace.
    La 2ème fonction écrit des std::string en les insérant directement dans le flux, chacun sont séparé par std::endl.
    La 3ème fonction écrit des objets statiques en appelant une méthode que je redéfini dans la classe de l'objet.
    La 4ème fonction écrit des objets dynamiques en appelant une méthode sur un objet (une clé) que j'insère dans la classe de l'objet à partir d'une macro. (Ceci me permet de récupéré le type dynamique à l'exécution et d'appeler la fonction de la bonne classe)

    Tout est sérialiser à partir de plusieurs archives qui contiennent le flux (exactement comme avec boost!) et je veux que cette archive choisisse la bonne fonction à appeler suivant le type de l'objet. (Ceci m'éviterais d'avoir des erreurs en compilation parce que l'objet ne contient pas de variable nommé key par exemple.)

    J'ai donc essayé de faire quelque chose comme ceci :

    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
     
     template <class O,
                  class = typename std::enable_if<!std::is_same<O, std::string>::value
                  && !std::is_fundamental<O>::value
                  && std::is_member_function_pointer<void(O::*)(OTextArchive&)>::value
                  && std::is_member_object_pointer<decltype(&O::key)>::value>::type>
        void operator() (O& object) {
            if (typeid(decltype(object)) == typeid(object)) {
                object.serialize(*this);
            } else {
                object.key.register_object(&object);
                object.key.serialize_object(*this, 0);
            }
        }
        template <class O,
                  class... D,
                  class = typename std::enable_if<!std::is_fundamental<O>::value>::type,
                  class = typename std::enable_if<std::is_member_function_pointer<void(O::*)(OTextArchive&)>::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...) {
            object.serialize(*this);
        }
        template <class O,
                  class = typename std::enable_if<!std::is_same<O, std::string>::value
                  && !std::is_fundamental<O>::value
                  && std::is_member_function_pointer<void(O::*)(OTextArchive&)>::value
                  && std::is_member_object_pointer<decltype(&O::key)>::value>::type>
        void operator() (O* object) {
            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++;
            }
        }
        template <class O,
                  class... D,
                  class = typename std::enable_if<!std::is_fundamental<O>::value>::type,
                  class = typename std::enable_if<std::is_member_function_pointer<void(O::*)(OTextArchive&)>::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) {
            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 {
                std::pair<unsigned long long int, unsigned long long int> newAddress (reinterpret_cast<unsigned long long int>(object), nbSerialized);
                adresses.insert(newAddress);
                buffer<<newAddress.second<<" ";
                object->serialize(*this);
                nbSerialized++;
            }
        }
        template <typename T,
              class... D,
              class = typename std::enable_if<std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<!sizeof...(D)>::type>
        void operator() (T& data, D...) {
            buffer<<data<<" ";
        }
         template <typename T,
              class... D,
              class = typename std::enable_if<!std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<std::is_same<T, std::string>::value>::type,
              class = typename std::enable_if<!sizeof...(D)>::type>
        void operator() (T& data, D...) {
            buffer<<data<<"\n";
        }
        template <typename T,
              class... D,
              class = typename std::enable_if<std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<!sizeof...(D)>::type>
        void operator() (T* data, D...) {
            std::map<unsigned long long int, unsigned long long int>::iterator it = adresses.find(reinterpret_cast<unsigned long long int>(data));
            if (it != adresses.end()) {
                buffer<<it->second;
            } else {
                std::pair<unsigned long long int, unsigned long long int> newAddress (reinterpret_cast<unsigned long long int>(data), nbSerialized);
                adresses.insert(newAddress);
                buffer<<newAddress.second;
                buffer<<*data<<" ";
                nbSerialized++;
            }
        }
        template <typename T,
              class... D,
              class = typename std::enable_if<std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<std::is_same<T, std::string>::value>::type,
              class = typename std::enable_if<!sizeof...(D)>::type>
        void operator() (T* data, D...) {
            std::map<unsigned long long int, unsigned long long int>::iterator it = adresses.find(reinterpret_cast<unsigned long long int>(data));
            if (it != adresses.end()) {
                buffer<<it->second;
            } else {
                std::pair<unsigned long long int, unsigned long long int> newAddress (reinterpret_cast<unsigned long long int>(data), nbSerialized);
                adresses.insert(newAddress);
                buffer<<newAddress.second;
                buffer<<*data<<"\n";
                nbSerialized++;
            }
        }
        template <class O,
                  class = typename std::enable_if<std::is_member_function_pointer<void(O::*)(OTextArchive&)>::value && !std::is_polymorphic<O>::value && !std::is_same<O, std::string>::value>::type>
        void operator() (std::vector<O>& data) {
            std::size_t size = data.size();
            buffer<<size;
            for (unsigned int i = 0; i < data.size(); i++)
                 (*this)(data[i]);
        }

    Donc je veux que :

    Si l'objet n'est pas un type fondamental, ni un string, contient un pointeur de fonction prenant l'archive en paramètre et ne contient pas de variable nommé key, alors il me choisisse la 1ère fonction.

    Sinon si l'objet n'est pas un type fondamental, ni un string, contient un pointeur de fonction prenant l'archive en paramètre et contient une variable nommé key, alors il me choississe la deuxième fonction.

    Sinon si l'objet est un type fondamental il me choisisse la troisième fonction.

    Sinon si l'objet n'est pas un type fondamental mais un string, il me choisisse la dernière fonction.

    Malheureusement ça ne fonctionne pas, il me choisi la mauvaise fonction, par exemple, pour un type fondamental, il me choisi la 1ère et non pas la troisième :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ||=== 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|
    /usr/local/include/odfaeg/Core/archive.h||In instantiation of ‘void odfaeg::OTextArchive::operator()(O&, D ...) [with O = std::vector<unsigned char>; D = {}; <template-parameter-1-3> = void; <template-parameter-1-4> = void; <template-parameter-1-5> = void; <template-parameter-1-6> = void]’:|
    /usr/local/include/odfaeg/Graphics/image.hpp|257|required from ‘void odfaeg::Image::serialize(Archive&) [with Archive = odfaeg::OTextArchive]’|
    /usr/local/include/odfaeg/Core/archive.h|103|required from ‘void odfaeg::OTextArchive::operator()(O&, D ...) [with O = odfaeg::Image; D = {}; <template-parameter-1-3> = void; <template-parameter-1-4> = void; <template-parameter-1-5> = void; <template-parameter-1-6> = void]’|
    /usr/local/include/odfaeg/Graphics/texture.h|474|required from ‘void odfaeg::Texture::serialize(Archive&) [with Archive = odfaeg::OTextArchive]’|
    /usr/local/include/odfaeg/Core/archive.h|103|required from ‘void odfaeg::OTextArchive::operator()(O&, D ...) [with O = odfaeg::Texture; 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|26|required from here|
    /usr/local/include/odfaeg/Core/archive.h|103|error: ‘class std::vector<unsigned char>’ has no member named ‘serialize’|
    ||=== Build failed: 1 error(s), 7 warning(s) (0 minute(s), 2 second(s)) ===|
    Bref je ne comprend pas pourquoi le compilateur me choisi cette fonction (hors que la condition est fausse) plutôt que la 3ème.
    Sinon, comment faire pour que le compilateur me choisisse bien les bonnes fonctions.

    Merci d'avance pour vos réponses.
    Dernière modification par Invité ; 18/08/2014 à 10h15.

  2. #2
    Invité
    Invité(e)
    Par défaut Un programme tout bête pour comprendre.
    Re,
    j'ai essayé de faire un programme tout bête pour comprendre :
    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
     
    class Archive {
    public :
    template <typename T,
              class = typename std::enable_if<std::is_fundamental<T>::value>::type>
              void operator() (T&) {
        std::cout<<"fundamental type version"<<std::endl;
    }
    template <typename T,
              class... D,
              class = typename std::enable_if<!std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<std::is_same<T, std::string>::value>::type>
              void operator() (T&, D...) {
                  std::cout<<"string version"<<std::endl;
              }
    template <typename T,
              class...D,
              class = typename std::enable_if<!std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<!std::is_same<T, std::string>::value>::type,
              class = typename std::enable_if<std::is_member_function_pointer<void(T::*)(Archive&)>::value>::type,
              class = typename std::enable_if<!std::is_member_function_pointer<void(T::*)(Archive&, int)>::value>::type>
              void operator() (T&, D...) {
                  std::cout<<"static object version"<<std::endl;
              }
    template <typename T,
              class...D,
              class = typename std::enable_if<!std::is_fundamental<T>::value>::type,
              class = typename std::enable_if<!std::is_same<T, std::string>::value>::type,
              class = typename std::enable_if<std::is_member_function_pointer<void(T::*)(Archive&)>::value>::type,
              class = typename std::enable_if<std::is_member_function_pointer<void(T::*)(Archive&, int)>::value>::type,
              class = typename std::enable_if<!sizeof...(D)>::type>
              void operator() (T&, D...) {
                  std::cout<<"dynamic object version"<<std::endl;
              }
    };
    class StaticObject {
        void serialize (Archive & ar) {
        }
    };
    class DynamicObject {
        void serialize (Archive & ar, int i) {
        }
    };
    int main(int argc, char* args[])
    {
        Archive ar;
        int i = 0;
        std::string str = "a string";
        StaticObject so;
        DynamicObject dyo;
        std::cout<<std::is_member_function_pointer<void(StaticObject::*)(Archive&, int)>::value<<std::endl;
        ar (i);
        ar (str);
        ar (so);
        ar(dyo);
        return 0;   
    }

    Mais il va toujours dans la même fonction si l'objet est statique ou dynamique, pourquoi est ce que std::is_member_function_pointer il me renvoie vrai hors que la classe StaticObject ne contient pas de pointeur de fonction prenant en paramètre une Archive et un int ?
    Dernière modification par Invité ; 18/08/2014 à 12h56.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bon je crois comprendre maintenant pourquoi j'ai des problèmes.

    J'ai essayer ceci grâce au code que j'ai trouvé ici ce qui convient parfaitement dans mon cas :

    http://en.wikipedia.org/wiki/Substit...s_not_an_error

    Mais avec le second code, value me renvoie toujours 1 même si le typedef n'est pas dans ma classe :

    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
     
    template <typename T>
    struct has_typedef_key {
        // Types "yes" and "no" are guaranteed to have different sizes,
        // specifically sizeof(yes) == 1 and sizeof(no) == 2.
        typedef char yes[1];
        typedef char no[2];
     
        template <typename C>
        static yes& test(typename C::key*);
     
        template <typename>
        static no& test(...);
     
        // If the "sizeof" of the result of calling test<T>(0) would be equal to sizeof(yes),
        // the first overload worked and T has a nested type named foobar.
        static const bool value = sizeof(test<T>(0)) == sizeof(yes);
    };

    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
     
    class StaticObject {
        void serialize (Archive & ar) {
        }
    };
    class DynamicObject {
        void serialize (Archive & ar) {
     
        }
        typedef float key;
    };
    int main(int argc, char* args[])
    {
         std::cout<<has_typedef_key<StaticObject>::value<<std::endl;
         std::cout<<has_typedef_key<DynamicObject>::value<<std::endl;
    }

  4. #4
    Invité
    Invité(e)
    Par défaut
    Ho purée, j'ai remplacé class par struct et ça fonctionne, je ne comprends pas pourquoi, est ce que quelqu'un pourrait m'éclairer un peu la dessus ?
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    struct StaticObject {
        void serialize (Archive & ar) {
        }
    };
    struct DynamicObject {
        void serialize (Archive & ar) {
     
        }
        typedef float key;
    };
    Merci.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Peut-être le template n'apprécie-t-il pas que les membres qu'il cherche soient private?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Ha oui c'était ça merci!!!

    Pfiou pas évident à trouver comme erreur. :/

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    La 2ème fonction écrit des std::string en les insérant directement dans le flux, chacun sont séparé par std::endl.
    Je n'ai lu que cette partie du message, mais je m'interroge : Que va-t-il se passer si une chaîne contient un '\n' ?
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Ha oui tu as raison il me faudrait un système qui supprime les /n dans le chaîne avant de les écrire sinon ça va être gênant.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ou mieux, un système qui les échappe. Ou qui ne dépend pas d'un format texte.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

Discussions similaires

  1. Erreur Objet requis : 'this' --> Comprend pas!!
    Par Grozeil dans le forum ASP
    Réponses: 3
    Dernier message: 30/03/2005, 09h46
  2. [thread][methodologie]Quelque chose que je ne comprends pas!
    Par norkius dans le forum Général Java
    Réponses: 5
    Dernier message: 16/03/2005, 14h01
  3. sql ne comprend pas mon where!et me demande des parametres
    Par marie10 dans le forum Langage SQL
    Réponses: 10
    Dernier message: 20/04/2004, 11h08
  4. [Rave] un message que je ne comprends pas
    Par Clotilde dans le forum Rave
    Réponses: 2
    Dernier message: 30/09/2003, 21h46

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