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).
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 ?
mais je crois que je prefererais changer la locale pour la retablir apres.
Jean-Marc Bourguet
Michel Decima writes:
Vincent Richard 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.
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
Michel Decima <michel.decima@orange-ft.com> writes:
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.
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.
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.
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
James Kanze
Vincent Richard wrote:
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).
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 :
(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 :
Ç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.
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.
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: 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
Vincent Richard wrote:
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).
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 :
(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 :
Ç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.
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.
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@gmail.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
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).
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 :
(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 :
Ç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.
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.
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: 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
Vincent Richard
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".
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
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".
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) ?
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
James Kanze
Vincent Richard wrote:
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.
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: 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
Vincent Richard wrote:
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.
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@gmail.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
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.
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: 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