Stockez n'importe quel type avec Boost.Any
Par
Alp Mestan (Site perso de Alp) (Blog)
Cet article présente le module
Any
de la bibliothèque dont la réputation n'est plus à faire :
Boost
.
I. Introduction
II. Présentation du module Boost.Any
II-1. La classe boost::any
II-2. La classe bad_any_cast
II-3. Les fonctions de conversion
II-4. Les contraintes sur le type qui est contenu
III. Exemples d'utilisation
III-1. Utilisation de base
III-2. Mise en oeuvre de bad_any_cast
III-3. Exemple plus complexe
IV. Conclusion
V. Remerciements
I. Introduction
Le module Boost.Any permet de stocker une variable de n'importe quel type dans un objet de type
boost::any
, bien qu'il y ait des pré-requis sur le type en question, ce que nous verrons plus loin dans l'article.
Vous pouvez consulter la documentation officielle de Boost.Any à l'adresse suivante :
Boost.Any
II. Présentation du module Boost.Any
Comme vous pouvez le voir sur la documentation officielle de Boost.Any, la bibliothèque se "résume" à ceci.
Elements clés du module Boost.Any |
namespace boost {
class bad_any_cast;
class any;
template < typename T> T any_cast (any & );
template < typename T> T any_cast (const any & );
template < typename ValueType> const ValueType * any_cast (const any * );
template < typename ValueType> ValueType * any_cast (any * );
}
|
II-1. La classe boost::any
Nous n'étudierons pas ici le fonctionnement interne de la classe
boost::any
mais allons plutôt
regarder l'interface de cette dernière. Si toutefois vous désirez voir comment la classe
boost::any
fonctionne,
vous pouvez regarder
son code
.
Voici l'interface de la classe
boost::any
.
class any
{
public :
any ();
template < typename ValueType> any (const ValueType & value);
any (const any & other);
~ any ();
any & swap (any & rhs);
template < typename ValueType> any & operator = (const ValueType & rhs);
any & operator = (const any & rhs);
bool empty () const ;
const std:: type_info & type () const ;
} ;
|
Etudions maintenant chacun des éléments de l'interface de
boost::any
.
Les constructeurs :
-
any()
: initialise l'objet contenu (qui est un pointeur) à 0 ;
-
template <typename ValueType> any(const ValueType & value)
:
mets
value
dans l'objet contenu dans l'instance de
boost::any
;
-
any(const any & other)
: place dans l'instance courante l'objet contenu dans
other
;
Le destructeur : détruit l'objet contenu dans l'instance courante, s'il n'est pas déjà vide (0) ;
Les fonctions membres et opérateurs publics :
-
any & swap(any & rhs)
: échange le contenu de l'instance courante avec celui de
rhs
;
-
template <typename ValueType> any & operator=(const ValueType & rhs)
:
remplace l'objet contenu par l'instance courante par l'objet
rhs
;
-
any & operator=(const any & rhs)
: remplace l'objet contenu par l'instance courante par l'objet contenu par l'instance
rhs
;
-
bool empty() const
: retourne vrai si aucun objet n'est contenu par l'instance courante, faux sinon ;
-
const std::type_info & type() const
: retourne le
std::type_info
associé au type réel de l'objet contenu dans l'instance courante.
II-2. La classe bad_any_cast
La classe
boost::bad_any_cast
représente l'exception qui est levée par
boost::any_cast
(que nous verrons plus loin) en cas d'échec. Voici ce à quoi elle se résume :
class bad_any_cast : public std:: bad_cast {
public :
virtual const char * what () const ;
} ;
|
Voyons maintenant comment convertir un
boost::any
en un type précis, lorsque c'est possible.
II-3. Les fonctions de conversion
Voici le prototype des fonctions de conversion.
template < typename T> T any_cast (any & );
template < typename T> T any_cast (const any & );
template < typename ValueType> const ValueType * any_cast (const any * );
template < typename ValueType> ValueType * any_cast (any * );
|
Si l'on passe un pointeur à un
boost::any_cast
, ce dernier retourne un pointeur
vers l'objet contenu si la conversion est réussie, un pointeur nul sinon.
Si T est un type à sémantique de valeur,
boost::any_cast
retourne une copie de l'objet
contenu. Si T est une référence sur un type à sémantique de valeur,
boost::any_cast
retourne
une référence sur l'objet stocké. Tout cela bien sûr sous réserve que le type demandé et le type réel
de l'objet contenu soient compatibles.
II-4. Les contraintes sur le type qui est contenu
Les contraintes sur le type
ValueType
de l'objet que va stocker un
boost::any
sont celles-ci :
-
ValueType
doit être copiable ;
-
ValueType
doit être assignable ; toutes les formes d'assignation utilisables avec
ValueType
doivent
être
exception-safe
;
-
Le destructeur (si
ValueType
est une classe) ne doit lancer aucune exception, quoiqu'il arrive.
III. Exemples d'utilisation
Nous allons maintenant essayer de nous familiariser avec l'utilisation du module
Boost.Any
par le biais de quelques exemples.
Tout d'abord, sachez qu'il y a un en-tête de boost à inclure pour utiliser la classe
boost::any
, et que cette dernière est dans l'espace
de nom de boost.
Instructions indispensables pour l'utilisation de Boost.Any |
# include <boost/any.hpp>
using namespace boost;
|
III-1. Utilisation de base
# include <iostream>
# include <boost/any.hpp>
using namespace boost;
using namespace std;
int main ()
{
any a1 (5 );
cout < < any_cast< int > (a1) < < endl;
any a2 (' c ' );
cout < < any_cast< char > (a2) < < endl;
a1 = a2;
cout < < any_cast< char > (a1) < < endl;
return 0 ;
}
|
Ce code met en oeuvre les bases de l'utilisation de boost::any et des fonctions any_cast. Voyons maintenant le système d'exception.
III-2. Mise en oeuvre de bad_any_cast
Le module
Boost.Any
fournit une classe représentant une exception, lancée en cas d'échec de conversion. Vous pourrez la voir en oeuvre avec l'exemple suivant.
# include <iostream>
# include <boost/any.hpp>
using namespace boost;
using namespace std;
struct S
{
} ;
int main ()
{
S s;
any a (s);
try
{
char c = any_cast< char > (a);
}
catch (bad_any_cast& bac)
{
cout < < bac.what () < < endl;
}
return 0 ;
}
|
Les deux exemples précédents sont assez simples et soulignent les fonctionnalités clés de ce module. Nous allons maintenant regarder un dernier exemple, un peu plus compliqué,
qui sera surement plus parlant.
III-3. Exemple plus complexe
Voyons maintenant ce que peut donner le couplage de la classe
boost::any
à un conteneur
standard, comme
std::vector
.
# include <iostream>
# include <vector>
# include <algorithm>
# include <boost/any.hpp>
using namespace boost;
using namespace std;
class MaClasse
{
std:: string s;
public :
MaClasse (const std:: string& s_) : s (s_)
{ }
} ;
bool is_char (const any& a)
{
return a.type () = = typeid (char );
}
bool is_int (const any& a)
{
return a.type () = = typeid (int );
}
bool is_std_string (const any& a)
{
return any_cast< std:: string> (& a);
}
bool is_ma_classe (const any& a)
{
return a.type () = = typeid (MaClasse);
}
int main ()
{
int i1 = 2 ;
int i2 = 45 ;
int i3 = 2321 ;
char c1 = ' d ' ;
char c2 = ' v ' ;
char c3 = ' p ' ;
std:: string s1 = " Developpez " ;
std:: string s2 = " .com " ;
MaClasse mc1 (" Boost.Any " );
MaClasse mc2 (" permet de stocker n'importe quel type " );
vector< any> values;
values.push_back (i1);
values.push_back (i2);
values.push_back (i3);
values.push_back (c1);
values.push_back (c2);
values.push_back (c3);
values.push_back (s1);
values.push_back (s2);
values.push_back (mc1);
values.push_back (mc2);
cout < < " Nombre d'entiers : " < < count_if (values.begin (), values.end (), is_int) < < endl;
cout < < " Nombre de caracteres : " < < count_if (values.begin (), values.end (), is_char) < < endl;
cout < < " Nombre de std::string : " < < count_if (values.begin (), values.end (), is_std_string) < < endl;
cout < < " Nombre de MaClasse : " < < count_if (values.begin (), values.end (), is_ma_classe) < < endl;
return 0 ;
}
|
Nous pouvons remarquer au passage qu'un
std::vector<boost::any>
permet de stocker des données hétérogènes pouvant être d'un type presque quelconque.
IV. Conclusion
Cet article a donc introduit un petit mais non moindre module de la bibliothèque Boost, le module
Boost.Any
. Si vous
avez des questions, n'hésitez pas à vous rendre
sur le forum Boost de Developpez
,
en mettant en début de titre le tag
[Any]
.
V. Remerciements
Merci à ... pour la relecture de cet article.
Copyright © 2008 Alp Mestan.
Aucune reproduction, même partielle, ne peut être faite
de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.