Les m�canismes de localisation ont �t� con�us de telle sorte que le programmeur peut, s'il le d�sire (et s'il en a r�ellement le besoin), personnaliser leur fonctionnement. Ainsi, il est parfaitement possible de d�finir de nouvelles facettes, par exemple pour permettre la localisation des types de donn�es compl�mentaires d�finis par le programme. De m�me, il est possible de red�finir les m�thodes virtuelles des classes de gestion des facettes standards de la biblioth�que et de remplacer les facettes originales par des facettes personnalis�es. Cependant, il faut bien reconna�tre que la mani�re de proc�der n'est pas tr�s pratique, et en fait les m�canismes internes de gestion des facettes semblent �tre r�serv�s aux classes et aux m�thodes de la biblioth�que standard elle-m�me.
Comme il l'a �t� expliqu� dans la Section 16.1,
une facette n'est rien d'autre qu'une classe d�rivant de la classe locale::facet
et contenant une donn�e membre statique id
. Cette donn�e membre
est utilis�e par les classes de locale pour identifier le type de la facette et pour l'int�grer
dans le m�canisme de gestion des facettes standards.
L'exemple suivant montre comment on peut r�aliser deux facettes permettant d'encapsuler les sp�cificit�s d'un type de donn�e d�fini par le programme, le type answer_t. Ce type est suppos� permettre la cr�ation de variables contenant la r�ponse de l'utilisateur � une question. Ce n'est rien d'autre qu'une �num�ration contenant les valeurs no (pour la r�ponse n�gative), yes (pour l'affirmative), all (pour r�pondre par l'affirmative pour tout un ensemble d'�l�ments) et none (pour r�pondre par la n�gative pour tout un ensemble d'�l�ments).
Dans cet exemple, deux facettes sont d�finies : la facette
answerpunct, qui prend en charge la localisation des noms des diff�rentes valeurs
de l'�num�ration answer_t, et la facette answer_put, qui prend en charge
le formatage des valeurs de cette �num�ration dans un flux standard. L'op�rateur
operator<<
est �galement d�fini, afin de pr�senter la mani�re dont
ces facettes peuvent �tre utilis�es. La facette answer_get et l'op�rateur correspondant
operator>>
n'ont pas �t� d�finis et sont laiss�s en exercice pour le lecteur
int�ress�.
Exemple 16-6. D�finition de nouvelles facettes
#include <iostream> #include <locale> using namespace std; // Nouveau type de donn�e permettant de g�rer les r�ponses // aux questions (yes / no / all / none) : enum answer_t { no, yes, all, none }; // Facette prenant d�finissant les noms des r�ponses : template <class charT> class answerpunct : public locale::facet { public: // Les types de donn�es : typedef charT char_type; typedef basic_string<charT> string_type; // L'identifiant de la facette : static locale::id id; // Le constructeur : answerpunct(size_t refs = 0) : locale::facet(refs) { } // Les m�thodes permettant d'obtenir les noms des valeurs : string_type yesname() const { return do_yesname(); } string_type noname() const { return do_noname(); } string_type allname() const { return do_allname(); } string_type nonename() const { return do_nonename(); } protected: // Le destructeur : virtual ~answerpunct() { } // Les m�thodes virtuelles : virtual string_type do_yesname() const { return "yes"; } virtual string_type do_noname() const { return "no"; } virtual string_type do_allname() const { return "all"; } virtual string_type do_nonename() const { return "none"; } }; // Instanciation de l'identifiant de la facette answerpunct : template <class charT> locale::id answerpunct<charT>::id; // Facette prenant en charge le formatage des r�ponses : template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class answer_put : public locale::facet public: // Les types de donn�es : typedef charT char_type; typedef OutputIterator iter_type; typedef basic_string<charT> string_type; // L'identifiant de la facette : static locale::id id; // Le constructeur : answer_put(size_t refs = 0) : locale::facet(refs) { } // La m�thode de formatage publique : iter_type put(iter_type i, ios_base &flux, char_type remplissage, answer_t valeur) const { return do_put(i, flux, remplissage, valeur); } protected: // Le destructeur : virtual ~answer_put() { } // L'impl�mentation de la m�thode de formatage : virtual iter_type do_put(iter_type i, ios_base &flux, char_type remplissage, answer_t valeur) const { // R�cup�re la facette d�crivant les noms de types : const answerpunct<charT> &facet = use_facet<answerpunct<charT> >(flux.getloc()); // R�cup�ration du nom qui sera �crit : string_type result; switch (valeur) { case yes: result = facet.yesname(); break; case no: result = facet.noname(); break; case all: result = facet.allname(); break; case none: result = facet.nonename(); break; } // �criture de la valeur : const char *p = result.c_str(); while (*p != 0) { *i = *p; ++i; ++p; } return i; } }; // Instanciation de l'identifiant de la facette answer_put : template <class charT, class OutputIterator = ostreambuf_iterator<charT> > locale::id answer_put<charT, OutputIterator>::id; // Op�rateur permettant de formater une valeur // de type answer_t dans un flux de sortie : template <class charT, class Traits> basic_ostream<charT, Traits> &operator<<( basic_ostream<charT, Traits> &flux, answer_t valeur) { // Initialisation du flux de sortie : typename basic_ostream<charT, Traits>::sentry init(flux); if (init) { // R�cup�ration de la facette de gestion de ce type : const answer_put<charT> &facet = use_facet<answer_put<charT> >(flux.getloc()); // �criture des donn�es : facet.put(flux, flux, ' ', valeur); } return flux; } int main(void) { // Cr�e une nouvelle locale utilisant nos deux facettes : locale temp(locale(""), new answerpunct<char>); locale loc(temp, new answer_put<char>); // Installe cette locale dans le flux de sortie : cout.imbue(loc); // Affiche quelques valeurs de type answer_t : cout << yes << endl; cout << no << endl; cout << all << endl; cout << none << endl; return 0; }
Note�: Cet exemple, bien que d�j� compliqu�, passe sous silence un certain nombre de points qu'il faudrait th�oriquement prendre en compte pour r�aliser une impl�mentation correcte des facettes et des op�rateurs d'insertion et d'extraction des donn�es de type answer_t dans les flux standards. Il faudrait en effet traiter les cas d'erreurs lors des �critures sur le flux de sortie dans la m�thode
do_put
de la facette answer_put, capter les exceptions qui peuvent se produire, corriger l'�tat du flux d'entr�e / sortie au sein de l'op�rateuroperator<<
et relancer ces exceptions.De m�me, les param�tres de la locale ne sont absolument pas pris en compte dans la facette answerpunct, alors qu'une impl�mentation compl�te devrait s'en soucier. Pour cela, il faudrait r�cup�rer le nom de la locale incluse dans les flux d'entr�e / sortie d'une part, et d�finir une facette sp�cialis�e answerpunct_byname, en fonction du nom de laquelle les m�thodes
do_yesname
,do_noname
,do_allname
etdo_nonename
devraient s'adapter. La section suivante donne un exemple de red�finition d'une facette existante.
La red�finition des m�thodes de facettes d�j� existantes est l�g�rement
plus simple que l'�criture d'une nouvelle facette. En effet, il n'est plus n�cessaire de d�finir
la donn�e membre statique id
. De plus, seules les m�thodes qui doivent
r�ellement �tre red�finies doivent �tre r�crites.
L'exemple suivant pr�sente comment un programme peut red�finir
les m�thodes do_truename
et do_falsename
de la facette
standard numpunct_byname
afin d'en fournir une version localis�e en fran�ais.
Cela permet d'utiliser ces noms fran�ais dans les op�rations de formatage des flux d'entr�e / sortie
standards, lorsque le manipulateur boolalpha
a �t� utilis�.
Exemple 16-7. Sp�cialisation d'une facette existante
#include <iostream> #include <locale> #include <clocale> #include <cstring> using namespace std; // Facette destin�e � remplacer numpunct_byname : class MyNumpunct_byname : public numpunct_byname<char> { // Les noms des valeurs true et false : const char *m_truename; const char *m_falsename; public: MyNumpunct_byname(const char* nom) : numpunct_byname<char>(nom) { // D�termine le nom de la locale active : const char *loc = nom; if (strcmp(nom, "") == 0) { // R�cup�re le nom de la locale globale active : loc = setlocale(0, NULL); } // Prend en charge les noms fran�ais : if (strcmp(loc, "fr_FR") == 0) { m_truename = "vrai"; m_falsename = "faux"; } else { // Pour les autres locales, utilise les noms anglais : m_truename = "true"; m_falsename = "false"; } } protected: ~MyNumpunct_byname() { } string do_truename() const { return m_truename; } string do_falsename() const { return m_falsename; } }; int main(void) { // Fixe la locale globale du programme : locale::global(locale("")); // Cr�e une nouvelle locale utilisant notre facette : locale l(locale(""), new MyNumpunct_byname("")); // Installe cette locale dans le flux de sortie : cout.imbue(l); // Affiche deux bool�ens : cout << boolalpha << true << endl; cout << false << endl; return 0; }
Note�: La classe de base de la facette MyNumpunct_byname est la classe
numpunct_byname
parce que la facette a besoin de conna�tre le nom de la locale pour laquelle elle est construite. En effet, aucun autre m�canisme standard ne permet � une facette de r�cup�rer ce nom et donc de s'adapter aux diff�rentes locales existantes. Vous remarquerez que les facettes de formatage n'ont pas besoin de conna�tre ce nom puisqu'elles peuvent le r�cup�rer gr�ce � la m�thodename
de la locale du flux sur lequel elles travaillent.La facette MyNumpunct_byname utilise la fonction
setlocale
de la biblioth�que C pour r�cup�rer le nom de la locale courante si elle est initialis�e avec un nom vide. En r�alit�, elle devrait r�cup�rer ce nom par ses propres moyens et effectuer les traductions des noms des valeurs true et false par elle-m�me, car cela suppose que la locale globale du programme est initialis�e avec le m�me nom. C'est pour cela que le programme principal commence par appeler la m�thodeglobal
de la classe local avec comme param�tre une locale anonmyme. Cela dit, les m�canismes permettant � un programme de r�cup�rer les param�tres de la locale d�finie dans l'environnement d'ex�cution du programme sont sp�cifiques � chaque syst�me et ne peuvent donc pas �tre d�crits ici.Bien entendu, si d'autres langues que le fran�ais devaient �tre prises en compte, d'autre m�canismes plus g�n�riques devraient �galement �tre mis en place pour d�finir les noms des valeurs true et false afin d'�viter de compliquer exag�r�ment le code de la facette.
Pr�c�dent | Sommaire | Suivant |
Les facettes standards | Niveau sup�rieur | Les conteneurs |