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

C++ Discussion :

Interpréter une valeur d'un boost::any


Sujet :

C++

  1. #1
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut Interpréter une valeur d'un boost::any
    Bonjour,

    Je suis dans une situation où j'appelle une fonction virtuelle dont le resultat peut être d'un type different selon le contexte. J'ai donc déclaré la fonction en mettant boost::any en type de retour. Le problème est que j'ai du mal à restaurer le boost::any dans le type désiré initialement.

    Voici en gros mon contexte.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class context
    {
    public:
      template<typename T>
      T convert( const std::string& s ) const
      {
        return converter<T>::convert(*this, s);
      }
     
      virtual boost::any custom_convert( const std::string& s ) const = 0;
    };
    Je demande la conversion d'une chaîne dans un type connu en appelant context::convert<LeType>(s). Selon que je sache faire la conversion moi-même ou pas, une implémentation de la classe converter ci-dessous est choisie (c'est simplifié) :

    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
    // traite le cas général
    template<typename T>
    struct converter
    {
      T convert( const context& c, const std::string& s ) const;
    };
     
    // traite le cas particulier d'une référence à un objet quelconque.
    template<typename T>
    struct converter<const T&>
    {
      const T& convert( const context& c, const std::string& s ) const
      {
        // on demande à la classe fille de se charger de la conversion
        const boost::any result = c.custom_convert(s);
     
        // échoue si c.custom_convert a retourné un T* au lieu d'un const T*
        return *boost::any_cast<T>( &result );
      }
    };
    Le problème est au niveau du return ci dessus. Si le type de la valeur retournée par c.custom_convert(s) n'est pas exactement const T*, alors la conversion échoue. Même si c'est un T*. Ce n'est pas surprenant quand on regarde le code de boost::any, mais je cherche une solution de remplacement.

    J'ai essayé plusieurs pistes*:
    • remplacer le boost::any_cast<T> par boost::unsafe_any_cast<T>() ;
    • faire une sorte de boost::any maison, en gardant l'idée du placeholder/holder<T> et en ajoutant un cast utilisant un dynamic_cast ;
    • passer par un void* dans un boost::any maison et utiliser un reinterpret_cast

    Aucune n'a été satisfaisante. Soit j'ai un problème avec la présence ou non d'un const dans le type de retour de custom_convert(), soit c'est que le custom_convert me retourne un pointeur sur une classe mère du type attendu, qui pourrait bien se convertir avec un dynamic_cast mais qui ne passe pas avec le holder<T> et ne se reinterpret_cast pas correctement depuis un void*.

    La dernière piste que j'ai est de passer le type_info du résultat attendu en paramètre à custom_convert, et imposer à la classe fille de me retourner un résultat ayant exactement le même type_info ou d'échouer. Ça ne me plaît pas beaucoup alors j'aimerais avoir vos avis sur le sujet avant de me lancer.

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Boost.Any c'est sympa mais au final on tombe sur des problèmes de ce genre là.
    Du coup moi je préfère deux approches:
    • type maison avec erasure et visitor. C'est à dire un type de base maison, puis je fais dériver tous mes types ensuite.
    • boost.Variant et boost::static_visitor

  3. #3
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Est ce que ca a un sens qu'un utilisateur décide de retourner un T* et non un const T* dans le custon_convert ? Si c'est pas le cas je choisirais d'imposer cette condition dans le contrat.

  4. #4
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Citation Envoyé par poukill Voir le message
    Boost.Any c'est sympa mais au final on tombe sur des problèmes de ce genre là.
    Du coup moi je préfère deux approches:
    • type maison avec erasure et visitor. C'est à dire un type de base maison, puis je fais dériver tous mes types ensuite.
    • boost.Variant et boost::static_visitor
    J'ai regardé un peu le boost.Variant mais je n'ai pas de limite sur les types possibles, du coup boost.Any semblait plus pertinant.

    Citation Envoyé par Flob90 Voir le message
    Est ce que ca a un sens qu'un utilisateur décide de retourner un T* et non un const T* dans le custon_convert ? Si c'est pas le cas je choisirais d'imposer cette condition dans le contrat.
    Oui oui, ça a tout à fait un sens. Éventuellement je peux faire deux custom_convert, un qui attend un const et un qui attend un non const, mais je ne pense pas que ça résolve le cas où j'ai une classe B qui hérite de A, j'attends un B* et on me retourne un A*.

  5. #5
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Bon j'ai avancé un peu, je m'en suis finalement sorti en utilisant des void* et des static_cast. Je pense que je bidouillerai avec un union le jour où j'aurai besoin que le custom_convert ne retourne pas un pointeur.

    Je sens bien que ce genre de pratique va me donner des erreurs de segmentation dans quelques mois, quand j'aurai oublié, et que je vais galérer à trouver que ça vient de là…

    Au passage, est-ce que ça a un sens de faire un dynamic_cast<T*>( static_cast<T*>(v) ), où v serait un void*. Que se passe-t-il si v ne peut vraiment pas être casté en T* ? le dynamic_cast va le remarquer ou ça va planter ?

  6. #6
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Tu peux toujours appliquer un static_cast sur void* pour obtenir le type que tu veux, par contre si le type n'est pas bon ca risque de planter à l'execution.

    Ton dynamic_cast sert à rien, ton static_cast va te retourner un T* et caster de T* à T* avec un dynamic_cast (c'est spécifié dans la norme), ca ne fait rien. (n3126, section 5.2.7, paragraphe 3).

  7. #7
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par j-jorge Voir le message
    Bon j'ai avancé un peu, je m'en suis finalement sorti en utilisant des void* et des static_cast. Je pense que je bidouillerai avec un union le jour où j'aurai besoin que le custom_convert ne retourne pas un pointeur.

    Je sens bien que ce genre de pratique va me donner des erreurs de segmentation dans quelques mois, quand j'aurai oublié, et que je vais galérer à trouver que ça vient de là…

    Au passage, est-ce que ça a un sens de faire un dynamic_cast<T*>( static_cast<T*>(v) ), où v serait un void*. Que se passe-t-il si v ne peut vraiment pas être casté en T* ? le dynamic_cast va le remarquer ou ça va planter ?
    C'est surtout que ça va marcher dans certains cas, et pas dans d'autres - par exemple si le void* pointe sur une instance d'une classe héritant de plusieurs classes. L'héritage multiple peut poser des problèmes lors d'un case vers void* et en retour de void*.

    Pour ton problème spécifique, je penses que tu en demande trop à boost.any. Tu peux toujours jouer avec const_cast<> pour gérer le const, mais tu ne feras pas changer le type statique d'une variable aussi aisément ; si tu as un objet de type A* stocké, alors tu obtiendras un objet de type A* en sortie, et il faudra faire le dynamic_cast toi même.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  8. #8
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'arrive pas à voir l'interet à retourner desfois quelque chose de constant et desfois quelque chose qui ne l'est pas ! Je ne sais pas si Custom_convert sert ailleurs, mais si ce n'est pas le cas, alors c'est clair que tu peux imposer de retourner quelque chose de constant.

    En testant j'ai remarqué des erreures dans ton code, notamment l'utilisation de Convert comme méthode statique alors qu'elle ne l'est pas, et c'est surment const T* et pas T dans any_cast (ou alors je n'ai pas compris comment tu te sers de ton code, tu pourrais poster un exemple de classe dérivant de Context pour tester ?)

  9. #9
    Membre confirmé

    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 104
    Points : 614
    Points
    614
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    J'arrive pas à voir l'interet à retourner desfois quelque chose de constant et desfois quelque chose qui ne l'est pas ! Je ne sais pas si Custom_convert sert ailleurs, mais si ce n'est pas le cas, alors c'est clair que tu peux imposer de retourner quelque chose de constant.
    Pour situer un peu le tout, il s'agit d'une évolution de ce que j'avais fait pour cet article. En gros, j'ai des classes qui « exportent » des fonctions pouvant être ensuite appelées selon une chaîne de caractères représentant le nom de la fonction, et en passant un tableau de chaînes de caractères représentant les paramètres. Le problème de l'implémentation de l'article est que les appels sont restreints à un seul contexte (le paramètre du partron de classe de base_exportable) et j'ai besoin aujourd'hui de faire des appels dans des contextes différents.

    Si les paramètres attendus sont de type simples (entier, réel, booléen ou chaîne), je fais la conversion directe de la chaîne. Pour les autres types, je suppose que la chaîne représente un identifiant qui pourra être converti selon le contexte dans le type attendu par la fonction : c'est le boulot de la fonction virtuelle custom_convert(). Le paramètre attendu peut être un const ma_classe& tout comme un ma_classe& et il faut surtout que ça soit compatible avec le type retourné par custom_convert().

    Citation Envoyé par Flob90 Voir le message
    En testant j'ai remarqué des erreures dans ton code, notamment l'utilisation de Convert comme méthode statique alors qu'elle ne l'est pas, et c'est surment const T* et pas T dans any_cast (ou alors je n'ai pas compris comment tu te sers de ton code, tu pourrais poster un exemple de classe dérivant de Context pour tester ?)
    Le code est un peu brouillon, j'ai voulu simplifier pour l'exemple. Je peux donner les liens vers le dépôt svn du projet. Voici l'implémentation actuelle du converter, ainsi qu'une utilisation aux lignes 137-138 de ce fichier et l'équivalent de custom_convert dans ce fichier.

Discussions similaires

  1. Interpréter un attribut comme un chemin et non une valeur
    Par yo-stat dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 15/11/2013, 08h42
  2. Réponses: 10
    Dernier message: 05/03/2013, 15h38
  3. [DTD] [Entities] Interpréter les valeurs d'une DTD
    Par kij dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 20/02/2008, 15h39

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