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 :

Comment récupérer un élément d'un tuple avec une variable de type int!


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Comment récupérer un élément d'un tuple avec une variable de type int!
    Salut, en fait j'essaye de récupérer un élément d'un tuple via une variable de type int. (et non pas une constexpr)

    Cependant je ne trouve pas comment faire :
    J'ai essayé 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
     
    template <typename T, int i, bool>
        struct S {
                 static typename std::tuple_element<i, decltype(T::typelist)>::type actualType = std::tuple_element<i, decltype(T::typelist)>();
        };
        template<>
        template<typename T, int i>
        struct S<T, i, false>
        {
            static void get(int n, T& result)
            {
                //assert(false);
            }
        };
        template <typename T, int i>
        struct S<T, i, true> {
            static void get(int n, T& result) {
                switch(n) {
                    case 0 : {
                        actualType = std::get<i>(T::typelist);
                        break;
                    }
                        default : {
                        constexpr bool isGreater = (std::tuple_size<decltype(T::typelist)>::value > i + 1);
                        return S<T, i+1, isGreater>::get(n-1, result);
                        break;
                    }
                }
            }
            static typename std::tuple_element<i, decltype(T::typelist)>::type actualType;
        };

    Le problème c'est que si la variable statique n'est pas initialisée le compilateur râle, alors je ne sais pas comment je pourrais initializer cette variable statique et si y'a pas moyen je ne vois pas comment récupérer l'élément dans le tuple. :/
    J'ai cherché partout sur internet mais je n'ai rien trouvé, quelqu'un a t'il une solution ?

    Merci.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Haaaaaa voilà je pense que j'ai trouvé ce que je cherchais!


  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
    toujours pas, regarde bien, l'index est encore un parametre template, donc une constexpr.

    Mais tu peux t'en sortir avec un switch, si ton nombre d'élément est connu.

    Suppose que tu travaille avec un using my_tuple = tuple<int, int, double, int, double>.
    Dans ce cadre, tu peux créer les deux fonctions suivantes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    int get_int(my_tuple const& t, int i) {
        switch(i) {
            case 0: return get<0>(t);
            case 1: return get<1>(t);
            case 3: return get<3>(t);
            default: throw ...;
        }
    }
     
    double get_double(my_tuple const& t, int i) {
        switch(i) {
            case 2: return get<2>(t);
            case 4: return get<4>(t);
            default: throw ...;
        }
    }
    Qu'en penses-tu?
    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
    Invité
    Invité(e)
    Par défaut
    Mon nombre d'éléments n'est pas connu. :/

    Bref j'ai laissé tombé std::tuple qui ne répond pas à mes besoins.

    Et ici j'essaye de créer un tuple plus dynamique on va dire.

    Mais j'ai un autre problème, je ne sais pas comment passer un template à une classe template qui hérite d'une autre classe template :

    J'ai essayé ceci mais ça ne compile pas. :/

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template <size_t I, typename L, typename T>
    struct Element {
        T type;
    };
     
     
    template <size_t I, typename L, template <std::size_t I, typename L, typename T> class E>
    struct TypelistElement : public Element<I, L,class = allocator<T>> {
     
    };

    Le truc c'est que je voudrais accéder au type de l'élément de la typelist sans connaître T. (Car je connais T au départ quand je l'ajoute mais plus après quand je le récupère.

    C'est ça le problème. :/

  5. #5
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Et ici j'essaye de créer un tuple plus dynamique on va dire.
    Comme std::vector<boost::any> ? C'est du type erasure que tu veux ?

  6. #6
    Invité
    Invité(e)
    Par défaut
    Non, c'est plus compliqué que ça parce que avec boost::any tu es obligé de faire un cast pour le récupérer le type de la variable.

    Ce que je voudrais faire c'est un truc comme ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Any any(3);
    auto T = any.get();

  7. #7
    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
    auto n'est pas un type magique qui accepte subitement n'importe quoi. C'est un type précis, que tu n'écris pas pour plus de lisibilité.

    auto signifie: "mon cher compilateur, tu sais aussi bien que moi que c'est un vector<map<vector<int>, set<int>::const_iterator>::iterator>::const_iterator qu'il faut, alors je ne vais pas l'écrire"

    Il faut que le type soit non ambigu, et dans ton cas précis, ce n'est pas le cas.

    J'ai la nette impression que ton problème est de l'autre coté.
    Si tu ne trouves pas de solution simple à ton problème technique, c'est peut-être que ce n'est pas la technique à appliquer à ton problème réel.
    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

  8. #8
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Faudrait que tu redéfinisses ton besoin avec un exemple simple mais complet pour que l'on parte sur une bonne base

  9. #9
    Invité
    Invité(e)
    Par défaut
    Faudrait que tu redéfinisses ton besoin avec un exemple simple mais complet pour que l'on parte sur une bonne base
    Ok alors voici ce que je veux faire :

    Je voudrais passer à une classe de base le type de l'objet dérivé, et assigner à chaque type, un entier, ensuite, je voudrais récupérer le type de cet entier.

    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
     
    #ifndef ODFAEG_SERIALIZATION
    #define ODFAEG_SERIALIZATION
    #include "../Core/tuple.h"
    #include <tuple>
    namespace odfaeg {
    class Serializable {
        public :
        template <typename D>
        Serializable(D* type) {
            if (type != nullptr) {
                if (!odfaeg::details::typelist<decltype(typelist)>::exists(type)) {
                    typelist.add_type(type);
                    typeId = nbIds;
                    nbIds++;
                } else {
                    typeId = odfaeg::details::get_index<decltype(typelist)>::element(type);
                }
            }
        }
        template <typename Archive>
        void serialize(Archive & ar) {
        }
        int getType() {
            return typeId;
        }
        static TypeList<Serializable> typelist;
        static int nbIds;
        int typeId;
    };
    }
    #endif

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void operator<<(Serializable* serializable) {
            auto object = static_cast<decltype(odfaeg::details::get_type<decltype(serializable->typelist)>::element(serializable->getType))>(serializable);
            save(object);
        }

    La partie ou je sèche est comment lui dire que 0 c'est le type X, 1 le type Y, et récupérer ce type afin de faire un truc genre 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
     
    #ifndef TUPLE
    #define TUPLE
    #include <tuple>
    #include <memory>
    namespace odfaeg {
    namespace helper {
    template <int...> struct seq {};
    template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {
     
    };
    template<int ...S> struct gens<0, S...>{
        typedef seq<S...> type;
    };
    }
     
    template <size_t I, typename L, typename T>
    struct Element {
        T type;
    };
     
     
    template <size_t I, typename L, template <std::size_t I, typename L, typename T> class E, typename T, class = std::allocator<T>>
    struct TypelistElement : public Element<I, L, T> {
     
    };
     
    template <typename L>
    class TypeList {
       template <size_t I, typename T>
       using ElementType = typename TypelistElement<I, L, Element, T>::type;
       TypeList () {
           nbTypes = 0;
       }
       template <typename A>
       void add_type (A type) {
           static ElementType<nbTypes, A> elementtype = type;
           nbTypes++;
       }
       int getSize() {
           return nbTypes;
       }
       int nbTypes;
    };
     
     
     
    namespace details {
        template <typename L, int I=0, bool B=true>
        struct get_type {
        };
        template <typename L, int I>
        struct get_type <L, I, true> {
            template <size_t N>
            using ElementType = typename TypelistElement<N, L, Element>::type;
            static typename ElementType<I> (L list, int n) {
                if (n == 0)
                    return std::tuple_element<I, L>::type;
                constexpr bool isGreater = (I+1 > list.nbTypes) ? true : false;
                return get_type<L, I+1, isGreater>::get_type(list, n);
            }
        };
        template <typename L, int I>
        struct get_type <L, I, false> {
            template <size_t I, typename L, template <std::size_t I, typename L, typename T> class E, typename T>
            using elementtype = typename TypelistElement<I, L, template <std::size_t I, typename L, typename T> class E, typename T>::type;
            static typename elementtype (L list, int n) {
                assert(false);
            }
        };
        template <typename L,int I=0, bool=true>
        struct typelist {
     
        };
        template <typename L, int I>
        struct typelist<L, I, true> {
            template <typename T>
            static bool exists (L list, T type) {
                if (std::is_same<T, decltype(get_type<L, 0, true>::element(list, I))>::value)
                    return true;
                constexpr bool isGreater = (I+1 > list.nbTypes) ? true : false;
                return typelist<L, I+1, isGreater>::exists(list, type);
            }
        };
        template <typename L, int I>
        struct typelist<L, I, false> {
            template <typename T>
            static bool exists (L list, T type) {
                return false;
            }
        };
        template <typename L, int I=0,bool B=true>
        struct get_index {
        };
        template <typename L, int I>
        struct get_index <L, I, true> {
            template <typename T>
            static int element (L list, T type) {
                if (std::is_same<T, decltype(get_type<L, 0, true>::element(list, I))>::value) {
                    return I;
                }
                constexpr bool isGreater = (I+1 > list.nbTypes) ? true : false;
                get_index <L, I+1, isGreater>::element(list, type);
            }
        };
        template <typename L, int I>
        struct get_index <L, I, false> {
            template <typename T>
            static int element (L list, T type) {
                assert(false);
            }
        };
    }
     
    }
    #endif // TUPLE

    Je pensais donc déclarer à chaque fois une nouvelle spécialisation de template dans laquelle je stocke le type, et ensuite je récupère le type en recherchant la bonne spécialisation c'est à dire celle correspondant à l'id tu tuple et la typelist.

    Bref quelque chose qui semble un peu compliqué, car, la seule manière de générer des spécialisations de template c'est d'utiliser un template variadique et d'utiliser std::get. (Mais il faut que le tuple soit statique c'est à dire que le nombre d'élément du tuple soit connu à la compilation)

    Ce que je voudrais faire c'est un tuple dynamic dont le nombre d'élément n'est pas connu à la compilation.

  10. #10
    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
    ton operateur<< n'est pas template, donc le "auto" correspond à un type unique.
    (en fait, il correspondrait à un type unique pour chaque instanciation de la template, si c'en était une)

    Ce n'est pas ce que tu veux.
    essaie de ne pas passer par une variable temporaire pour bénéficier de la possibilité de surcharger de save

    De là, tu devrais pourvoir te passer de cette machinerie.
    ostream<< ne passe pas par des tuples, même quand tu as des héritages.
    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

  11. #11
    Invité
    Invité(e)
    Par défaut
    Le problème c'est que si je ne fait pas ça, il va m'appeler la fonction serialize de la classe de base si l'objet est polymorphique.

    Du coup il va m'appeler la fonction :
    template<typename A>
    serialize(A& archive)
    de la classe de base au lieu de celle de la classe dérivée :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template <typename C>
        void save (C object) {
            void(C::*func)(OTextArchive&) = &C::serialize;
            (object.*func)(*this);
        }
        void operator<<(Serializable* serializable) {
            auto object = static_cast<decltype(odfaeg::details::get_type<decltype(serializable->typelist)>::element(serializable->getType))>(serializable);
            save(object);
        }

    Donc ici la fonction de la classe Serialize qui ne fait rien.

  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
    Pour l'instant, je ne peux pas t'aider plus, je ne comprends pas ton contexte.
    Pourrais-tu nous donner une hiérarchie de sérializable, et le sérialiseur? qu'on comprenne un peu mieux ton problème?

    Parce que je ne vois pas de différence entre ton besoin et ostream.
    D'ailleurs, personnellement, je code toujours mes sérialiseurs comme une paire de stream?

    Tu as deux possibilités:
    1. dupliquer les fonctionnalités pour permettre d'écrire des fonctions différentes pour stream et serializer
    2. faire hériter serializer de ostream


    De là, plus de soucis, les pointés appellent leur opérateurs réels, et c'est bouclé.
    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
    Ha bon en faisant hériter Serializable de ostream ça marcherais ?

    Je ne savais pas, merci.

  14. #14
    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
    pas serializable, serializer.

    avec ostream, tu as:
    • le stream, qui sais que faire d'un int, d'un char*, etc
    • ta classe, qui contient du barouf
    • l'operateur<< que tu définis, pour expliquer à ostream que faire de ta classe.



    Ton processus de sérialisation suit normalement le même schéma
    • Le sérialiseur devrait savoir que faire des types primitifs,
    • chaque classe s'occupe de se qu'elle représente
    • des fonctions libres font la jonction.


    Donc fait hériter le sérialiseur de ostream, et immédiatement, tous les operator<<(ostream&, T const&) sont utilisables dessus.
    Ca demande un peu de travail sur lui, mais le reste sera tellement plus simple
    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

  15. #15
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Voir les facets pour le faire la sérialisation avec ostream/istream : http://en.cppreference.com/w/cpp/locale

Discussions similaires

  1. Réponses: 1
    Dernier message: 14/08/2011, 04h24
  2. Réponses: 10
    Dernier message: 06/05/2010, 20h51
  3. Réponses: 8
    Dernier message: 18/04/2008, 17h40
  4. Réponses: 15
    Dernier message: 10/05/2007, 13h36
  5. Réponses: 2
    Dernier message: 10/04/2007, 12h39

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