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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de cs_ntd
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2006
    Messages
    598
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Décembre 2006
    Messages : 598
    Par défaut Récupérer le type d'un param... => EDIT : Stocker des variables d'un type différents dans un même conteneneur
    [EDIT]
    Ancien titre : Récupérer le type d'un parametre et retourner un pointeur sur une valeur de ce type

    Je l'ai modifié car il ne correspondait plus au problème...
    [/EDIT]


    Bon dimanche à tous !

    Bon derrière ce titre mal tourné ce cache le fait que j'ai un petit souci de conception que je ne sais résoudre...

    En fait la problématique est la suivante :

    J'ai une classe que je vais appeler "Object". Le problème de cette classe est qu'elle est très générale : je ne sais absolument pas "quoi", et surtout que devra faire un objet de type Object...
    Et le principale problème était de pouvoir stocker des paramètres "d'évolution" de manière transparente, cependant les paramètres pouvait être de n'importe quel type.
    C'est pour ça que dans ma class "Objetc", j'ai un attribut membre "paramètre" de type "std::vector<long>", dans lequel je stock :

    les valeurs des pointeurs associés aux paramètres "réels"
    (Edit : d'ailleurs j'y pense : ne vaudrait il pas mieux stocker des pointeurs "void *" plutôt que des long ???)

    Pas de souci pour rentrer les adresses dans mon vector, par contre pour les sortir ...

    Bon pour les faires rentrer, j'ai une fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Object::param_push_back(void *param);
    et roule ma poule.
    Après au niveau de l'appel, ça reste assez user-friendly :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Object object1(...);
    A_type param1;
    object1.param_push_back(&param1);
    Et si après je veux le récupérer, je n'ai pour l'instant pas trouver mieux que de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::vector<long>::iterator it;
    ...
    A_type param2 = *((A_type*)(*it));
    Ce qui est très moyen au niveau de l'"use-friendly".
    L'ideal serait une fonction par exemple "get_param()", pour que l'on puissee faire "param2 = get_param();" voir "param2 = *get_param();".

    J'ai bien penser à faire un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void* get_param(void *param, vector<long>::iterator jt)
    {
        return ((typeof(*param)*)(*jt)
    }
    
    ...
    
    A_type param2(...);
    param2 = *get_param(&param2,it);
    Mais bien sur ça marche pas, j'ai plein d'erreurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void* is not a pointer-to-object type
    Et en plus j'utilise "typeof()" ce qui d'après ce que j'ai lu semblerai être une fonction propre à gcc, donc ça me plait pas vraiment.

    Est_ce que par miracle quelqu'un aurait une idée de comment je pourrait, en passant un paramètre dans ma fonction get_param, comment récupérer, soit un pointeur sur la valeur, soit la valeur directement ?

    Je vous remercie par avance de toute l'aide que vous voudrait bien m'apporter

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Je te conseille de t'intéresser vivement à Boost.Any (ou au minimum au type erasure). tout ce que tu décris ressemble plus à du code présentant beaucoup de défaut, d'approximation, limite des erreurs là où il existe des solutions adéquates avec cette approche.

  3. #3
    Membre éclairé Avatar de cs_ntd
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2006
    Messages
    598
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Décembre 2006
    Messages : 598
    Par défaut
    Wow merci de ta réponse

    Je ne connaissai pas trop l'un, et pas du tout les "type erasure" !

    Le seul problème est que c'est dans un cadre scolaire : je ne peut donc pas utiliser boost (pas standard et c'est pas moi qui l'ai fait).
    Après pour le type erasure, pourquoi mais bon :

    1) J'ai pas tout compris c'est un peu au dessus de mes compétences (surtout sur la fin le truc avec les politiques et tout, j'ai du louper un truc ^^).
    2) Je ne suis pas sur que ça corresponde bien à ce que je veux faire, C'est à dire :

    Je souhaite, que lorsqu'un futur utilisateur utilisera ma librairie, qu'il ne se préocupe pas de ce qu'il y a derrière, c'est à dire, qu'il ne s'occupe pas de faire dériver ses int ou ses double d'une classe base...
    Après, j'ai certains objets, dont je ne connais pas du tout l'utilisation qui en sera fait, mais je sais qu'il y aura besoin de sauvegarder certaines informations sur cet objet bien précis (et dans mon idée, ces informations devaient devenir le plus proche possible d'attributs de l'objet).

    Dans l'absolue, je ne voudrait pas que cela soit plus compliquer que de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int a = 5;
    obj.insert(&a);
     
    //Puis plus tard pour récupérer
     
    int b = *get_info(position);
    A l'utilisateur par contre de se débrouiller pour se rappeler quel est le type de quoi, et à quelles données correspond quelle position...

    Est-ce qu'on peut vraiment faire aussi simple avec le type erasure ??? Est-ce quon peut vraiment cacher la partie héritage à l'utilisateur ? Si vraiment on peut faire aussi simple pourquoi pas...

    Sinon en répondant je crois que j'ai trouvé la solution à mon problème en fait
    Voici ce à quoi j'ai pensé (et qui fonctionne d'après mes tests) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    typedef std::vector<void *> void_vect; //Ou vector<long> ? C'était ma première hypothèse à la base, mais ça n'a pas l'air de changer grand chose
    typedef void_vect::const_iterator position;
    class Object
    {
        void_vect  all_type_vect;
        position it;
    public:
        Object();
        ~Object();
     
     
        position push_back(void *);
     
        template<class T>
        T* get_pointed(position);
    }
     
    position Object::push_back(void *param)
    {
        all_type_vect.push_back(param);
        return all_type_vect.end()--;
    }
     
    template<class T>
    T* get_pointed(position jt)
    {
        return ((T*)(*jt));
    }
    Ce qui pourrait s'utiliser avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    struct A{...}
     
    int main()
    {
        Object obj;
        int i = 0;
        A a(...);
     
        position pos = obj.push_back(&i);
        obj.push_back(&a);
        obj.push_back(new int(5));
        obj.push_back(new A(...));
     
        std::cout << "int i = " << *get_pointed<int>(pos) << endl; //Récupération de la véritable valeur.
        int b = *get_pointed<A>(pos + 1); //Copie de la valeur pointée dans un nouvel objet
        A *b = get_pointed<int>(pos + 2); //Passage de l'adresse à b
        return 0;
    }
    Mais j'avoue que je n'ai pas encore pensé à la destruction de l'objet... Mis à part cela vous en pensez quoi franchement ?
    Ca marche ? marche pas ?
    En comparaison du type erasure ça parait plus simple/moins simple ?
    Plus casse gueule/moins casse gueule ?
    Y a un truc auquel je n'ai pas pensé ?

    Merci encore de toutes vos réponses

  4. #4
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Dans la mesure ou c'est de l'OO, je te conseil de faire une interface qui possède les méthode getSave et setRestore. Mais j'avoue que j'ai pas bien compris.

    Je te proposerai aussi le Factory (notamment abstract factory), juste pour voir si ça correspond pas à ton problème...

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    @cs_ntd : le type erasure te permet de ne pas passer par un void* pour stocker tes objets mais par un type défini et donc bénéficier du typage statique du C++. Conjugué avec une fonction comme any_cast<T>, tu peux utiliser une 'union générique' comme tu le souhaites tout en bénéficiant des avantages du typage.
    Ta solution avec des void* (pas des long qui seront dépendant du compilo/plateforme) nécessite des reinterpret_cast à tout va et détruisent la sécurité du typage.
    Reprends le tuto sur le type erasure à tête reposée et lit bien la partie Réécrivons boost::any. Elle se propose de redéfinir Boost.Any ... donc tu peux t'en inspirer sans avoir à utiliser Boost. J'ai quand même l'impression que cela correspond à ton besoin : avoir un conteneur qui puisse contenir n'importe quel objet et le retrouver ensuite avec le bon type.

  6. #6
    Membre éclairé Avatar de cs_ntd
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2006
    Messages
    598
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Décembre 2006
    Messages : 598
    Par défaut
    Re tout le monde,

    Soit dit en passant, ça doit ête le post que j'ai mis le plus long temps à écrire, tellement j'ai marqué de truc, puis tout effacé, puis tout réécris

    @3DArchi :

    Oué ça correspond en effet, il me semble... Le seul problème, c'est que y a un endroit ou j'ai pas compris comment la magie opère mais le résultat reste là.

    Ce que je ne comprend pas, c'est ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class any
    {
    	value_base* v;
    	
    	public:
    	any() : v(0) { }
    	
    	template <class value_type>
    	any(const value_type& v_) : v(new value<value_type>(v_)) { }
    	
    	~any() { delete v; }
    };
    [/COLOR]
    1) Dans la partie any():v(0) on fait vraiment appel au constructeur d'un pointeur ?? ça veut dire qu'on initialise un pointeur avec l'adresse 0 ?

    2) Ensuite, c'est dans le code, par exemple "any a = 4"... Coment est-ce que ça marche ? Je ne saisi pas du tout le mécanisme... J'aurais eu tendance à écrire (c'est sans doute faux, mais bon) quelque chose du genre :
    any<int> a(4) ou encore
    any a<int>(4)
    vu que le constructeur est un constructeur "template"... Ca veut dire que le constructeur récupère tout seul le bon type ??? La pour moi c'est très très mystérieux :o

    Sinon pour le reste... Presque tout compris !

    Ou pas ! Je crois que c'est encore trop subtil pour moi, parcequ'au final, je ne vois pas tout le temps la différence avec mon code, ni la raison de certains choix (dans le re-codage de any).

    Par exemple, il est dit (partie Limites et conclusion) que :
    on ne peut pas récupérer l'information que l'on a perdu sur le type précis de départ
    Donc au final, un objet "any" contient bien un pointeur sur un type "value_base", qui est certe un type, mais qui ne correspond à rien de "concret". Donc au final on a une adresse sur un objet qui peut être n'importe quoi (c'est le but nan ?)
    Mais moi de mon coté, je stock aussi des pointeurs ayant perdu le type sur lequel ils pointaient au départ... Alors si en plus, dans ma fonction "get_pointed", si à la place de faire une conversion (T*), je fait une conversion "dynamic_cast<T>", je ne vois plus de différence du tout...

    Tellement de choses à apprendre et comprendre encore ... ...

    @Lavock :
    Question noms, j'ai pris les premiers trucs qui me sont passés par la tête ^^.
    Sinon l'abstract factory baaa je crois que je comprend encore moins bien le mécanisme que pour le type erasure , mais pour ce que j'en ai compris, il me semble que ça ne me serve pas trop dans le cas présent :

    pouvoir stocker un objet de type T1 dans un conteneur
    puis stocker un autre objet, de type T2 dans le même conteneur
    etc...
    puis récupérer ces valeurs
    Le tout d'une manière transparente à l'utilisateur...
    (càd qu'il n'ai pas à se soucier de savoir si c'est un vector ou autre que j'utilise, si j'ai défini un type any ou pas, et sans qu'il est besoin de faire hériter ses types de quelque chose...)


    Je ne saurais vous remercier tous assez pour votre aide

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 19/03/2013, 20h46
  2. Réponses: 1
    Dernier message: 14/06/2011, 18h02
  3. Réponses: 5
    Dernier message: 05/02/2009, 16h20
  4. Réponses: 14
    Dernier message: 13/07/2007, 12h05
  5. Type structure en param d'une fonction
    Par totoche dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 28/02/2007, 14h26

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