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.
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 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; };
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.
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 ); } };
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.
Partager