C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Ignorer temporairement une locale

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Vincent Richard
Guest





PostPosted: Wed Nov 08, 2006 9:27 pm    Post subject: Ignorer temporairement une locale Reply with quote



Bonjour,

Mon titre n'est peut-être pas très bien choisi. J'ai besoin d'écrire des
nombres dans un flux sans qu'ils soient formattés (comme avec la locale
"C" par défaut).

Soit le code suivant :

----------------------------------------------------------------------
#include <iostream>
#include <locale>

int main()
{
std::locale loc("fr_FR.UTF-8");
std::cout.imbue(loc);

plop(std::cout);
}

void plop(std::ostream& os)
{
os << 123456 << std::endl;
}
----------------------------------------------------------------------

La sortie affichée est, sur ma machine : "123 456" (avec un espace
comme séparateur de milliers).

J'ai besoin que la sortie soit "123456" (brut, sans aucun formattage
donc), tout en laissant le changement de locale dans main (la fonction
plop est en réalité dans une bibliothèque à part).

Est-ce possible ? Existe-t-il un manipulateur qui permet d'inhiber,
temporairement, la locale courante ?

Il me semble qu'il doit être possible de la changer, puis de rétablir
l'originale ensuite, mais ce n'est pas trop ce que je cherche...

En passant, à part les nombres (entiers ou flottants), quels types
sont susceptibles d'êtres "localisés" en sortie ?

Merci d'avance !

Vincent
Back to top
Jean-Marc Bourguet
Guest





PostPosted: Wed Nov 08, 2006 10:14 pm    Post subject: Re: Ignorer temporairement une locale Reply with quote



Vincent Richard <vincent@vincent-richard.net> writes:

Quote:
Est-ce possible ? Existe-t-il un manipulateur qui permet d'inhiber,
temporairement, la locale courante ?

Je n'en vois pas.

Quote:
Il me semble qu'il doit être possible de la changer, puis de rétablir
l'originale ensuite, mais ce n'est pas trop ce que je cherche...

Utiliser un ostream temporaire qui a le meme streambuf me semble etre alors
une solution a investiguer. Je ne peux garantir qu'elle fonctionne.

Quote:
En passant, à part les nombres (entiers ou flottants), quels types sont
susceptibles d'êtres "localisés" en sortie ?

Les bool peuvent l'etre egalement. D'autres types si ceux qui les ont
fournis ont pris la peine de definir ce qu'il faut.

A+

--
Jean-Marc
Back to top
Michel Decima
Guest





PostPosted: Wed Nov 08, 2006 10:45 pm    Post subject: Re: Ignorer temporairement une locale Reply with quote



Jean-Marc Bourguet a écrit :
Quote:
Vincent Richard <vincent@vincent-richard.net> writes:

Il me semble qu'il doit être possible de la changer, puis de rétablir
l'originale ensuite, mais ce n'est pas trop ce que je cherche...

Utiliser un ostream temporaire qui a le meme streambuf me semble etre alors
une solution a investiguer. Je ne peux garantir qu'elle fonctionne.

il y a aussi ca:

void plop(std::ostream& os)
{
std::ostringstream fmt;
fmt << 123456;
os << fmt.str();
}

mais je crois que je prefererais changer la locale pour la retablir apres.
Back to top
Jean-Marc Bourguet
Guest





PostPosted: Wed Nov 08, 2006 11:23 pm    Post subject: Re: Ignorer temporairement une locale Reply with quote

Michel Decima <michel.decima@orange-ft.com> writes:

Quote:
Jean-Marc Bourguet a écrit :
Vincent Richard <vincent@vincent-richard.net> writes:

Il me semble qu'il doit être possible de la changer, puis de rétablir
l'originale ensuite, mais ce n'est pas trop ce que je cherche...
Utiliser un ostream temporaire qui a le meme streambuf me semble etre
alors
une solution a investiguer. Je ne peux garantir qu'elle fonctionne.

il y a aussi ca:

void plop(std::ostream& os)
{
std::ostringstream fmt;
fmt << 123456;
os << fmt.str();
}

mais je crois que je prefererais changer la locale pour la retablir apres.

A noter qu'il faut etre prudent en changeant la locale et ne pas imbuer
std::locale::classic(): il faut la recuperer et ne changer que les facets
qu'il faut; en particulier, changer codecvt me semble etre une mauvaise
idee.

A+

--
Jean-Marc
Back to top
Vincent Richard
Guest





PostPosted: Thu Nov 09, 2006 10:12 am    Post subject: Re: Ignorer temporairement une locale Reply with quote

James Kanze wrote:

Quote:
Un autre alternatif, c'est de formatter dans un
std::ostringstream, et puis simplement sortir la chaîne
ainsi générée

Merci, c'est la solution que j'ai retenue, même si ça fait
un peu "marteau pour tuer une mouche".

Une petite question à ce propos : je suppose que ça dépend des
implémentations, mais en général qu'est-ce que la construction
d'un ostringstream induit (réservation de mémoire, etc.) ?

Est-ce que les implémentations sont optimisées pour ne pas trop
pénaliser la création de ces objets (du point de vue temps CPU,
mais aussi consommation mémoire) ?

Vincent
Back to top
James Kanze
Guest





PostPosted: Thu Nov 09, 2006 10:12 am    Post subject: Re: Ignorer temporairement une locale Reply with quote

Vincent Richard wrote:

Quote:
Mon titre n'est peut-être pas très bien choisi. J'ai besoin
d'écrire des nombres dans un flux sans qu'ils soient formattés
(comme avec la locale "C" par défaut).

Soit le code suivant :

----------------------------------------------------------------------
#include <iostream
#include <locale

int main()
{
std::locale loc("fr_FR.UTF-8");
std::cout.imbue(loc);

plop(std::cout);
}

void plop(std::ostream& os)
{
os << 123456 << std::endl;
}
----------------------------------------------------------------------

La sortie affichée est, sur ma machine : "123 456" (avec un espace
comme séparateur de milliers).

J'ai besoin que la sortie soit "123456" (brut, sans aucun formattage
donc), tout en laissant le changement de locale dans main (la fonction
plop est en réalité dans une bibliothèque à part).

Est-ce possible ? Existe-t-il un manipulateur qui permet d'inhiber,
temporairement, la locale courante ?

Pas tout fait, mais c'est facile d'en faire. La fonction imbue()
renvoie le locale dont se servait du flux avant ; il y a aussi
une fonction getloc() pour le lire sans y toucher. Dans plop,
donc :

void
plop( std::ostream& os )
{
std::locale saved = os.getloc() ;
os.imbue( std::locale::classic() ) ;
os << 123456 << std::endl ;
os.imbue( saved ) ;
}

(Sauf qu'évidemment, on se servira du RAII pour la restauration
de l'ancien état.)

Néaumoins, j'y serais très méfiant. Modifier le locale du flux
modifie aussi le locale du filebuf dont il se sert ; imbue sur
le flux appelle imbue sur le streambuf, et si ce streambuf est
un filebuf, on a la précondition : « If the file is not
positioned at its beginning and the encoding of the current
locale as determined by a_codecvt .encoding() is state-dependent
(22.2.1.4.2) then that facet is the same as the corresponding
facet of loc. ». S'il y a une risque d'un encodage qui dépend
de l'état (et selon la façon que c'est implémenté, UTF-8
pourrait en être un), il faut un étap en plus :

void
plop( std::ostream& os )
{
std::locale saved = os.getloc() ;
os.imbue( std::locale( std::locale::classic(),
saved,
std::locale::ctype ) ;
os << 123456 << std::endl ;
os.imbue( saved ) ;
}

Un autre alternatif, c'est de formatter dans un
std::ostringstream, et puis simplement sortir la chaîne ainsi
générée :

void
plop( std::ostream& os )
{
std::ostringstream tmp ;
tmp.imbue( std::locale::classic() ) ;
tmp << 123456 ;
os << tmp.rdbuf() ;
}

Ça a aussi l'avantage (ou désavantage, selon ce qu'on veut) de
te rendre indépendant des paramètres de formattage actif lors de
l'appel. Donc, si dans main, l'utilisateur a fait
std::cout << std::hex, en tripotant le locale, tu sors encore
en hexadécimal, tandis qu'avec le stringstream temporaire, tes
sorties sont en décimal, quelque soit le formattage actuellement
en vigueur dans la fonction appelante.

Quote:
Il me semble qu'il doit être possible de la changer, puis de
rétablir l'originale ensuite, mais ce n'est pas trop ce que je
cherche...

C'est cependant comme ça que ça marche.

Quote:
En passant, à part les nombres (entiers ou flottants), quels types
sont susceptibles d'êtres "localisés" en sortie ?

Selon ce que tu entends par « localisés » : l'encodage du
fichier dépend du locale (y compris en mode binary !). Donc,
tous les octets que tu sors sont « localisés ». Sinon, qui
sait : la norme ne prévoit que le formattage des types
arithmétiques, des pointeurs et des chaînes de caractères. Le
format des types arithmétiques dépend toujours du locale, celui
des pointeurs, selon l'implémentatoin, et en fait, les chaînes
ne sont pas formattées, quelque soit le locale. Mais la norme ne
dit rien sur des types utilisateurs (sauf std::complex, qui
n'est pas localisé !), qui en font la plupart des sorties. Il
faut donc chaque fois régarder la documentation. (Je
m'attendrais, par exemple, que boost::date_time ou diverses
classes monétaires soient localisées.)

--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
James Kanze
Guest





PostPosted: Thu Nov 09, 2006 9:58 pm    Post subject: Re: Ignorer temporairement une locale Reply with quote

Vincent Richard wrote:
Quote:
James Kanze wrote:

Un autre alternatif, c'est de formatter dans un
std::ostringstream, et puis simplement sortir la chaîne
ainsi générée

Merci, c'est la solution que j'ai retenue, même si ça fait
un peu "marteau pour tuer une mouche".

Il ne doit pas l'être. En général, [io]stringstream doit être la
solution « habituelle » pour convertir de et vers std::string.
D'autant plus quand tu as des exigeances particulières de
formattage.

Quote:
Une petite question à ce propos : je suppose que ça dépend des
implémentations, mais en général qu'est-ce que la construction
d'un ostringstream induit (réservation de mémoire, etc.) ?

Est-ce que les implémentations sont optimisées pour ne pas trop
pénaliser la création de ces objets (du point de vue temps CPU,
mais aussi consommation mémoire) ?

À vrai dire, je ne sais pas. A priori, il n'y a aucune raison
pour qu'elle reserve de la mémoire avant d'en avoir besoin, pour
la chaîne même. Mais traditionnellement, les implémenteurs
semblent avoir fait un maximum pour rendre les iostream aussi
lourds que possible.

--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.