OVH Cloud OVH Cloud

surcharge d'un ostream

13 réponses
Avatar
amerio
Bonjour,
J'ai un ostream surchargé, avec des manipulateurs maison spécifiques.
En simplifiant :
myostream derive publiquement de std::basic_ostream<...>
et manip est un manipulateur à paramétre pour un myostream
je me suis inspiré de ca :
http://www.two-sdg.demon.co.uk/curbralan/papers/WritingStreamManipulators.html

donc je peux faire :
myostream out;
out << manip(1);
et manip(1) manipule un membre privé de myostream (c'est un friend)

Mon probleme :
out << manip(1); marche tres bien
out << manip(1) << "toto"; marche aussi
out << "toto" << manip(1); ne compile meme pas car operator<<(string&) renvoie un
ostream& de base, et manip attend un myostream&.

Donc, avez vous une solution assez elegante ?
Je ne peux bien sur pas reecrire tous les operator<< pour les types de base, car je veux
que myostream accepte aussi les types utilisateurs (c'est qd meme le but des stream !)

10 réponses

1 2
Avatar
kanze
"amerio" wrote in message
news:<fgflb.69950$...

J'ai un ostream surchargé, avec des manipulateurs maison spécifiques.
En simplifiant :
myostream derive publiquement de std::basic_ostream<...>
et manip est un manipulateur à paramétre pour un myostream


Pourquoi faire ? Qu'est-ce que ton flux fait différemment de ostream ?

En général, la seule raison d'hériter de ostream, c'est de fournir les
constructeurs de commodité qui utilisent un streambuf propre. Sur le
modèle de ofstream ou de ostringstream, par exemple.

Du coup, ou bien, ton manipulateur fait quelque chose qui s'applique en
fait à tous les flux, ou bien, il lui faut un streambuf particulier.
Sans savoir lequel, c'est impossible à donner une bonne solution.

je me suis inspiré de ca :
http://www.two-sdg.demon.co.uk/curbralan/papers/WritingStreamManipulators.html


Ça m'étonne qu'il les crée pour un type dérivé de ostream seulement.

donc je peux faire :
myostream out;
out << manip(1);
et manip(1) manipule un membre privé de myostream (c'est un friend)

Mon probleme :
out << manip(1); marche tres bien
out << manip(1) << "toto"; marche aussi
out << "toto" << manip(1); ne compile meme pas car operator<<(string&) renvoie un
ostream& de base, et manip attend un myostream&.


Tout à fait.

Donc, avez vous une solution assez elegante ?


J'en ai plusieurs, mais d'abord, il faut que je sache le problème.

Je ne peux bien sur pas reecrire tous les operator<< pour les types de
base, car je veux que myostream accepte aussi les types utilisateurs
(c'est qd meme le but des stream !)


C'est le moindre des problèmes : à quoi sert les templates, après tout.

Dériver d'un ostream, comme tu as fait, en ajoutant des membres privés,
est prèsque toujours une errur. Mais sans connaître le problème que tu
essaies de résoudre de cette façon, c'est impossible à te dire ce que tu
dois faire à la place.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Bruno Personnel
wrote:

"amerio" wrote in message
news:<fgflb.69950$...


J'ai un ostream surchargé, avec des manipulateurs maison spécifiques.
En simplifiant :
myostream derive publiquement de std::basic_ostream<...>
et manip est un manipulateur à paramétre pour un myostream



Pourquoi faire ? Qu'est-ce que ton flux fait différemment de ostream ?

En général, la seule raison d'hériter de ostream, c'est de fournir les
constructeurs de commodité qui utilisent un streambuf propre. Sur le
modèle de ofstream ou de ostringstream, par exemple.

Du coup, ou bien, ton manipulateur fait quelque chose qui s'applique en
fait à tous les flux, ou bien, il lui faut un streambuf particulier.
Sans savoir lequel, c'est impossible à donner une bonne solution.


je me suis inspiré de ca :
http://www.two-sdg.demon.co.uk/curbralan/papers/WritingStreamManipulators.html



Ça m'étonne qu'il les crée pour un type dérivé de ostream seulement.


donc je peux faire :
myostream out;
out << manip(1);
et manip(1) manipule un membre privé de myostream (c'est un friend)



Mon probleme :
out << manip(1); marche tres bien
out << manip(1) << "toto"; marche aussi
out << "toto" << manip(1); ne compile meme pas car operator<<(string&) renvoie un
ostream& de base, et manip attend un myostream&.



Tout à fait.


Donc, avez vous une solution assez elegante ?



J'en ai plusieurs, mais d'abord, il faut que je sache le problème.


Je ne peux bien sur pas reecrire tous les operator<< pour les types de
base, car je veux que myostream accepte aussi les types utilisateurs
(c'est qd meme le but des stream !)



C'est le moindre des problèmes : à quoi sert les templates, après tout.

Dériver d'un ostream, comme tu as fait, en ajoutant des membres privés,
est prèsque toujours une errur. Mais sans connaître le problème que tu
essaies de résoudre de cette façon, c'est impossible à te dire ce que tu
dois faire à la place.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Je ne peux que seconder James dans sa réponse. Maintenant, à priori, si
ton manipulateur doit avoir un comportement dépendant de l'entrée, le
moyen le plus simple est d'utiliser le RTTI.

Bruno


Avatar
amerio
J'ai un ostream surchargé, avec des manipulateurs maison spécifiques.
En simplifiant :
myostream derive publiquement de std::basic_ostream<...>
et manip est un manipulateur à paramétre pour un myostream


Pourquoi faire ? Qu'est-ce que ton flux fait différemment de ostream ?


Mon stream implemente un streambuf spécialisé, et doit gerer une stack de propriété
(états).

En général, la seule raison d'hériter de ostream, c'est de fournir les
constructeurs de commodité qui utilisent un streambuf propre. Sur le
modèle de ofstream ou de ostringstream, par exemple.


Exactement.

Du coup, ou bien, ton manipulateur fait quelque chose qui s'applique en
fait à tous les flux, ou bien, il lui faut un streambuf particulier.
Sans savoir lequel, c'est impossible à donner une bonne solution.


Mon manipulateur ne peut pas s'appliquer à un stream générique.
Son but est de modifier plusieus états spécifiques du flux. Je donner un exempel après.

je me suis inspiré de ca :
http://www.two-sdg.demon.co.uk/curbralan/papers/WritingStreamManipulators.html


Ça m'étonne qu'il les crée pour un type dérivé de ostream seulement.
Non, il donne juste un exemple de création de manipulateur avec paramètre, c'est tout.

Il ne dérive pas de nouveau stream.

[...]
Dériver d'un ostream, comme tu as fait, en ajoutant des membres privés,

est prèsque toujours une errur. Mais sans connaître le problème que tu
essaies de résoudre de cette façon, c'est impossible à te dire ce que tu
dois faire à la place.


Ok, partons du problème initial alors.
Je veux implémenter un stream gérant des attributs supplémentaires (couleur, taille de
police, position du curseur, etc.)
et je veux que ces attributs soit maintenus dans une pile.
Pour donner un exemple je veux pouvoir faire :

output << "hello" << color(255,0,0) << "rouge" << push << color(0,0,255) << "bleu" << pop
<< "rouge" << render;
output << "hello" << size(10) << "petit" << size(20) << "gros" << render;
etc...
Le dernier manip "render" effectuant un rendu du buffer avec les bons attributs.
Je suis ouvert à toute idée :-)


Avatar
kanze
"amerio" wrote in message
news:<H6Blb.86663$...
J'ai un ostream surchargé, avec des manipulateurs maison
spécifiques. En simplifiant :

myostream derive publiquement de std::basic_ostream<...> et manip
est un manipulateur à paramétre pour un myostream


Pourquoi faire ? Qu'est-ce que ton flux fait différemment de ostream ?


Mon stream implemente un streambuf spécialisé, et doit gerer une stack
de propriété (états).

En général, la seule raison d'hériter de ostream, c'est de fournir
les constructeurs de commodité qui utilisent un streambuf propre.
Sur le modèle de ofstream ou de ostringstream, par exemple.


Exactement.

Du coup, ou bien, ton manipulateur fait quelque chose qui s'applique
en fait à tous les flux, ou bien, il lui faut un streambuf
particulier. Sans savoir lequel, c'est impossible à donner une bonne
solution.


Mon manipulateur ne peut pas s'appliquer à un stream générique. Son
but est de modifier plusieus états spécifiques du flux. Je donner un
exempel après.

je me suis inspiré de ca :
http://www.two-sdg.demon.co.uk/curbralan/papers/WritingStreamManipulators.html


Ça m'étonne qu'il les crée pour un type dérivé de ostream seulement.


Non, il donne juste un exemple de création de manipulateur avec
paramètre, c'est tout. Il ne dérive pas de nouveau stream.

[...]


Dériver d'un ostream, comme tu as fait, en ajoutant des membres
privés, est prèsque toujours une errur. Mais sans connaître le
problème que tu essaies de résoudre de cette façon, c'est impossible
à te dire ce que tu dois faire à la place.


Ok, partons du problème initial alors.

Je veux implémenter un stream gérant des attributs supplémentaires
(couleur, taille de police, position du curseur, etc.) et je veux que
ces attributs soit maintenus dans une pile. Pour donner un exemple je
veux pouvoir faire :

output << "hello" << color(255,0,0) << "rouge" << push << color(0,0,255) << "bleu" << pop
<< "rouge" << render;
output << "hello" << size(10) << "petit" << size(20) << "gros" << render;
etc...
Le dernier manip "render" effectuant un rendu du buffer avec les bons
attributs. Je suis ouvert à toute idée :-)


Une première remarque -- je ne suis pas sûr que les flux soit le bon
idiome pour ça. Mais passons...

Dans ce cas, je réimplémenterais effectivement tous les opérateurs <<,
mais avec des templates, donc :

class MyStream
{
public :
MyStream( std::ostream& dest ) : myDest( dest ) {}

std::ostream& stream() { return myDest }
private :
std::ostream myDest ;
} ;

template< typename T >
MyStream&
operator<<( MyStream& dest, T const& value )
{
dest.stream() << value ;
}

Avec l'appartenance, et non l'héritage, et une fonction template, sans
doute avec pas mal de fonctions non template (pour tout les types
speciaux qui t'interessent) en surcharge.

L'avantage, par rapport à d'autres solutions, c'est qu'il y a des
vérifications des types au moment de la compilation -- tes manipulateurs
ne marche que sur des MyStream, jamais sur d'autres types de flux.

Si tu veux appeler une fonction existante qui insère quelque chose dans
le flux, tu appelles la fonction avec myStream.stream().

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



Avatar
amerio
Je veux implémenter un stream gérant des attributs supplémentaires
(couleur, taille de police, position du curseur, etc.) et je veux que
ces attributs soit maintenus dans une pile. Pour donner un exemple je
veux pouvoir faire :

output << "hello" << color(255,0,0) << "rouge" << push << color(0,0,255) <<
"bleu" << pop << "rouge" << render;
output << "hello" << size(10) << "petit" << size(20) << "gros" << render;
etc...
Le dernier manip "render" effectuant un rendu du buffer avec les bons
attributs. Je suis ouvert à toute idée :-)


Une première remarque -- je ne suis pas sûr que les flux soit le bon
idiome pour ça. Mais passons...


Pourquoi ? A cause du 'render' final ? Il est facultatif, et puis on peut le voir comme un
'flush' des streams standards.
Et je veux absolument profiter des operator<< pour des types personnalisés qui ont cet
opérateur. Je ne veux pas avoir a modifier ces classes ou ajouter des fonctions libres en
plus qui utiliserais ces operateur derrière (ce que je trouve assez lourd !)

Mais sinon, quelle(s) autre(s) idée(s) aurais tu ?


Dans ce cas, je réimplémenterais effectivement tous les opérateurs <<,
mais avec des templates, donc :

class MyStream
{
public :
MyStream( std::ostream& dest ) : myDest( dest ) {}

std::ostream& stream() { return myDest }
private :
std::ostream myDest ;
} ;

template< typename T >
MyStream&
operator<<( MyStream& dest, T const& value )
{
dest.stream() << value ;
}


Manque return dest; je pense
Mais je vois le principe ;-)

Avec l'appartenance, et non l'héritage, et une fonction template, sans
doute avec pas mal de fonctions non template (pour tout les types
speciaux qui t'interessent) en surcharge.

L'avantage, par rapport à d'autres solutions, c'est qu'il y a des
vérifications des types au moment de la compilation -- tes manipulateurs
ne marche que sur des MyStream, jamais sur d'autres types de flux.


Oui, c'est bien ce qui m'interessent, car une verification en runtime avec dynamic_cast me
gene (moins beau)

Si tu veux appeler une fonction existante qui insère quelque chose dans
le flux, tu appelles la fonction avec myStream.stream().


Comme pour l'operator<< templatisé ci-dessus ... Ok
Ben je vais tester ca, encore merci :-)


Avatar
kanze
"amerio" wrote in message
news:<fKOlb.96952$...

Je veux implémenter un stream gérant des attributs supplémentaires
(couleur, taille de police, position du curseur, etc.) et je veux
que ces attributs soit maintenus dans une pile. Pour donner un
exemple je veux pouvoir faire :

output << "hello" << color(255,0,0) << "rouge" << push << color(0,0,255) <<
"bleu" << pop << "rouge" << render;
output << "hello" << size(10) << "petit" << size(20) << "gros" << render;
etc...
Le dernier manip "render" effectuant un rendu du buffer avec les
bons attributs. Je suis ouvert à toute idée :-)


Une première remarque -- je ne suis pas sûr que les flux soit le bon
idiome pour ça. Mais passons...


Pourquoi ? A cause du 'render' final ?


Surtout parce que je n'avait pas régardé en détail, et qu'effectivement,
la nécessité d'une commande « render » provoque des doutes. Alors, la
plupart du temps, quand de telles questions se posent, il s'agit des
étiquettes et des boutons dans une interface graphique ; dans de tels
cas, des attributes comme la couleur ou la police de caractères sont des
propriétés de l'élément graphique, non des propriétés embriquées dans le
flux du texte. Et les éléments graphiques, ça n'a rien à voir avec un
flux.

Même ici, je ne suis pas tout à fait sûr. Quand on considère du texte
formatté, disons comme fait un outil comme TeX, il ne s'agit pas autant
d'une flux, que d'une suite de flux, rassemblés d'une façon
hièrarchique, parfois verticalement, parfois horizontalement. Je n'ai
jamais fait une telle application -- je ne peux donc pas dire ce que je
ferais réelement. Disons que si je n'exclus pas pour l'instance
l'utilisation d'un flux, je ne le vois pas comme allant de soi non plus.

Mais puisqu'il s'agit d'un flux de texte ici, pourquoi pas surcharger
sync dans ton streambuf pour faire la rendition (et l'appeler dans le
destructeur). Parce qu'en fin de compte, la rendition, c'est bien une
synchronisation du support réel avec le flux, non ?

Il est facultatif, et puis on peut le voir comme un 'flush' des
streams standards.


Donc, pourquoi pas utiliser flush ? (C'est réelement une question,
motivée par la curiosité, plutôt qu'un désir de trouver une faute dans
ta conception.)

Et je veux absolument profiter des operator<< pour des types
personnalisés qui ont cet opérateur.


La, je suis tout à fait d'accord.

Je ne veux pas avoir a modifier ces classes ou ajouter des fonctions
libres en plus qui utiliserais ces operateur derrière (ce que je
trouve assez lourd !)

Mais sinon, quelle(s) autre(s) idée(s) aurais tu ?


Tu pourrais toujours jeter un coup d'oeil sur GB_Format, à ma site. Il
s'occupe du formattage en se servant des operator<< existant, mais sans
considérer le tout comme un flux.

Mais ce que je voyais plutôt, c'est une séparation éventuelle de la
génération du texte et de la spécification de ces attributes de
renditions. Maintenant que je vois que ces attributes sont bel et bien
embriquées dans le texte, je crois qu'effectivement l'idiome de flux
pourrait convenir.

Sans toutefois une héritage de ostream ; je ne crois pas que tes flux
soient échangeable avec un ostream.

Dans ce cas, je réimplémenterais effectivement tous les
opérateurs <<, mais avec des templates, donc :

class MyStream
{
public :
MyStream( std::ostream& dest ) : myDest( dest ) {}

std::ostream& stream() { return myDest }
private :
std::ostream myDest ;
} ;

template< typename T >
MyStream&
operator<<( MyStream& dest, T const& value )
{
dest.stream() << value ;
}


Manque return dest; je pense


Toute à fait:-). Aussi un peu de gestion des erreurs.

Mais je vois le principe ;-)


C'est l'essentiel. L'idée, c'est que tu définis ton propre flux,
indépendamment de std::ostream. Au moins en ce qui concerne
l'utilisateur -- c'est claire qu'on ne veut pas dupliquer le code des
conversions. Donc, un ostream member et des fonctions templatées qui
s'en servent.

Selon le cas, tu pourrais le trouver plus commode d'utiliser un seul
std::ostream, qui renvoie à ton propre streambuf, ou d'utiliser un
nouveau std::ostream (souvent un std::ostringstream en fait) chaque
fois. Ou un melange : un flux par rendition, par exemple.

Avec l'appartenance, et non l'héritage, et une fonction template,
sans doute avec pas mal de fonctions non template (pour tout les
types speciaux qui t'interessent) en surcharge.

L'avantage, par rapport à d'autres solutions, c'est qu'il y a des
vérifications des types au moment de la compilation -- tes
manipulateurs ne marche que sur des MyStream, jamais sur d'autres
types de flux.


Oui, c'est bien ce qui m'interessent, car une verification en runtime
avec dynamic_cast me gene (moins beau)


Ça dépend toujours de ce que tu fais. Si tu ajoutes un manipulateur qui
n'a de sens que pour un type de flux donné, et qui est raisonablement un
no-op pour tous les autres types de flux, la solution avec dynamic_cast
n'est pas forcément mauvaise. Mais d'après le peu que je vois, je crois
que tu as réelement un type de flux qui n'est pas directement apparanté
aux flux classique.

En fin de compte, je crois que la question critique, c'est ce qu'il faut
faire si le dynamic_cast échoue. Si le comportement correct, c'est
simplement de ne rien faire, le dynamic_cast est potentiellement une
bonne solution. Si son échec est significatif d'une erreur dans le
programme, en revanche, c'est mieux de l'éviter si on peut.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



Avatar
amerio
Une première remarque -- je ne suis pas sûr que les flux soit le bon
idiome pour ça. Mais passons...


Pourquoi ? A cause du 'render' final ?


Surtout parce que je n'avait pas régardé en détail, et qu'effectivement,
la nécessité d'une commande « render » provoque des doutes. Alors, la
plupart du temps, quand de telles questions se posent, il s'agit des
étiquettes et des boutons dans une interface graphique ; dans de tels
cas, des attributes comme la couleur ou la police de caractères sont des
propriétés de l'élément graphique, non des propriétés embriquées dans le
flux du texte. Et les éléments graphiques, ça n'a rien à voir avec un
flux.

Même ici, je ne suis pas tout à fait sûr. Quand on considère du texte
formatté, disons comme fait un outil comme TeX, il ne s'agit pas autant
d'une flux, que d'une suite de flux, rassemblés d'une façon
hièrarchique, parfois verticalement, parfois horizontalement. Je n'ai
jamais fait une telle application -- je ne peux donc pas dire ce que je
ferais réelement. Disons que si je n'exclus pas pour l'instance
l'utilisation d'un flux, je ne le vois pas comme allant de soi non plus.


Oui, je comprend... En fait, mon probleme est entre un flux standard (je dois pouvoir
ecrire comme sur cout, aussi facilement, pour du debug), et du Tex (je dois avoir des
sorties formatés, alignement, couleur, taille...)

Il s'agit au final d'afficher du texte 2D (pour un jeu), et l'utilisation doit être
similaire pour les infos de debug, pour une console utilisateur, et pour les elements
d'interface (gui).
Dans la pratique, ce n'est pas le même "stream" qui servira a tout cela, mais tous
utiliseront au final un seul "service" de rendu.
Evidement, pour la gui, le texte est encapsulé par l'element gui lui-même, et les
attributs (color, etc.) sont des propriétés de l'element (que le flux utilise).
Pour des raisons de performances, tous les elements de texte sont dessinés (rendu) en une
seule fois. Le modificateur 'render' ne déclenche pas le rendu en fait (apres c'est du
detail d'implemenattion). C'est un flush en fait (mais comme flush est appelé par endl, je
veux pourvoir garder la syntaxe endl independanment sans faire un 'render').

Mais puisqu'il s'agit d'un flux de texte ici, pourquoi pas surcharger
sync dans ton streambuf pour faire la rendition (et l'appeler dans le
destructeur). Parce qu'en fin de compte, la rendition, c'est bien une
synchronisation du support réel avec le flux, non ?


Oui, mais ce rendu n'est pas synchrone, et n'a lieu qu'une fois par 'frame'. "render" est
plus un "check-point".

Il est facultatif, et puis on peut le voir comme un 'flush' des
streams standards.


Donc, pourquoi pas utiliser flush ? (C'est réelement une question,
motivée par la curiosité, plutôt qu'un désir de trouver une faute dans
ta conception.)


flush est appelé par endl. Et je ne veux pas que endl soit percu de cette facon.


Et je veux absolument profiter des operator<< pour des types
personnalisés qui ont cet opérateur.


La, je suis tout à fait d'accord.

Je ne veux pas avoir a modifier ces classes ou ajouter des fonctions
libres en plus qui utiliserais ces operateur derrière (ce que je
trouve assez lourd !)

Mais sinon, quelle(s) autre(s) idée(s) aurais tu ?


Tu pourrais toujours jeter un coup d'oeil sur GB_Format, à ma site. Il
s'occupe du formattage en se servant des operator<< existant, mais sans
considérer le tout comme un flux.

Mais ce que je voyais plutôt, c'est une séparation éventuelle de la
génération du texte et de la spécification de ces attributes de
renditions. Maintenant que je vois que ces attributes sont bel et bien
embriquées dans le texte, je crois qu'effectivement l'idiome de flux
pourrait convenir.

Sans toutefois une héritage de ostream ; je ne crois pas que tes flux
soient échangeable avec un ostream.


Non, en effet. Et ce n'est pas le but. La composition me convient tres bien !
Disons que seul l'aspect "flux" est important.
En effet, l'output va servir aussi pour du debug sur l'ecran, avec la même facilité qu'un
cout.

Pour résumer, disons qu'il y a un service de rendu de texte formatté, qui lit un certain
format (ca pourrais etre du XML ou autre ! aucune importance). Et ce service sert à
plusieurs choses. Du debug (type cout), des infos type HeadUpDisplay (formatté), une
console (formattée aussi) et une interface GUI 2D.
Et je preferes ecrire :
hud << push << bold << "hello" << pop
plutot que
hud.Push().Tag("B").Text("Hello").Pop()



Avatar
Loïc Joly
wrote:

Alors, la
plupart du temps, quand de telles questions se posent, il s'agit des
étiquettes et des boutons dans une interface graphique ; dans de tels
cas, des attributes comme la couleur ou la police de caractères sont des
propriétés de l'élément graphique, non des propriétés embriquées dans le
flux du texte. Et les éléments graphiques, ça n'a rien à voir avec un
flux.


QT propose une alternative que je trouve sympa : Quand on tape du text
dans un élément d'IHM, il est possible d'entre quelques tags "HTML" pour
mettre en forme une partie du texte. Ca offre plus de flexibilité que de
la mise en forme au niveau de l'élément graphique lui même, et c'est
assez souple à écrire.

--
Loïc

Avatar
kanze
Loïc Joly wrote in message
news:<bnbs66$qmh$...
wrote:

Alors, la plupart du temps, quand de telles questions se posent, il
s'agit des étiquettes et des boutons dans une interface graphique ;
dans de tels cas, des attributes comme la couleur ou la police de
caractères sont des propriétés de l'élément graphique, non des
propriétés embriquées dans le flux du texte. Et les éléments
graphiques, ça n'a rien à voir avec un flux.


QT propose une alternative que je trouve sympa : Quand on tape du text
dans un élément d'IHM, il est possible d'entre quelques tags "HTML"
pour mettre en forme une partie du texte. Ca offre plus de flexibilité
que de la mise en forme au niveau de l'élément graphique lui même, et
c'est assez souple à écrire.


Swing aussi offre quelque chose de semblable en Java : un « renderer »
de texte HTML.

Dans l'ensemble, je trouve la solution proposée plus élégant. Dans le
code même, on dit ce qu'on veut au moyen des manipulateurs. Ou d'autre
chose ; comme j'ai dit, je ne suis pas sûr si le flux est le modèle qui
convient pour quelque chose qui est, en fin de compte, deux
dimensionnel. Par la suite, rien n'empêche (tout au contraire) le
« renderer » à générer de l'HTML, du LaTex, ou tout autre format voulu.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
kanze
"amerio" wrote in message
news:<W_5mb.111886$...

[...]
Mais puisqu'il s'agit d'un flux de texte ici, pourquoi pas
surcharger sync dans ton streambuf pour faire la rendition (et
l'appeler dans le destructeur). Parce qu'en fin de compte, la
rendition, c'est bien une synchronisation du support réel avec le
flux, non ?


Oui, mais ce rendu n'est pas synchrone, et n'a lieu qu'une fois par
'frame'. "render" est plus un "check-point".


Attention. Ce n'est pas la signification du sync dans les flux
classique. Ou p't-êtr' ben qu'oui -- la signification exacte est assez
floue (exprès, pour laisser la liberté aux flux dérivés de définir ce
qui convient le plus). Mais le concepte de synchronisation entre le flux
interne (avec bufferisation, etc.) et le flux « soujacent » y est.

Il est facultatif, et puis on peut le voir comme un 'flush' des
streams standards.


Donc, pourquoi pas utiliser flush ? (C'est réelement une question,
motivée par la curiosité, plutôt qu'un désir de trouver une faute
dans ta conception.)


flush est appelé par endl. Et je ne veux pas que endl soit percu de
cette facon.


Pourquoi. Si je n'ai pas besoin de la rendition à ce moment-là,
j'utilise 'n', et non endl. Si j'utilise endl, c'est bien que je veux
la synchronisation immédiate entre le flux interne et la représentation
externe.

Et je veux absolument profiter des operator<< pour des types
personnalisés qui ont cet opérateur.


La, je suis tout à fait d'accord.

Je ne veux pas avoir a modifier ces classes ou ajouter des
fonctions libres en plus qui utiliserais ces operateur derrière (ce
que je trouve assez lourd !)

Mais sinon, quelle(s) autre(s) idée(s) aurais tu ?


Tu pourrais toujours jeter un coup d'oeil sur GB_Format, à ma
site. Il s'occupe du formattage en se servant des operator<<
existant, mais sans considérer le tout comme un flux.

Mais ce que je voyais plutôt, c'est une séparation éventuelle de la
génération du texte et de la spécification de ces attributes de
renditions. Maintenant que je vois que ces attributes sont bel et
bien embriquées dans le texte, je crois qu'effectivement l'idiome de
flux pourrait convenir.

Sans toutefois une héritage de ostream ; je ne crois pas que tes
flux soient échangeable avec un ostream.


Non, en effet. Et ce n'est pas le but. La composition me convient tres
bien ! Disons que seul l'aspect "flux" est important. En effet,
l'output va servir aussi pour du debug sur l'ecran, avec la même
facilité qu'un cout.


La facilité est toujours une question d'habitude, et de ce qu'on veut
faire. En fait, cout ne modèle qu'un flux linéaire de texte, sans
attributes. Si tu supportes des attributes embriquées dans le texte, ou
des positionnement ou du formattage en deux dimensions, l'utilisation
serait plus complex que l'utilisation de cout. Quelque soit le modèle
choisi.

Pour résumer, disons qu'il y a un service de rendu de texte formatté,
qui lit un certain format (ca pourrais etre du XML ou autre ! aucune
importance). Et ce service sert à plusieurs choses. Du debug (type
cout), des infos type HeadUpDisplay (formatté), une console (formattée
aussi) et une interface GUI 2D.

Et je preferes ecrire :
hud << push << bold << "hello" << pop
plutot que
hud.Push().Tag("B").Text("Hello").Pop()


Pourquoi ?

En passant, est-ce que tu as considéré aussi la possibilité d'utiliser
la durée de vie des temporaires à la place de pop ? Grosso modo, que les
attributes positionnées dans une expression soit automatiquement poppées
à la fin de l'expression. Que tu utilises << ou des appels de fonctions,
ça peut simplifier l'utilisation, et surtout réduire des erreurs dues à
l'oublie d'un pop. (Je ne sais pas si ça convient à ton utilisation ou
non, mais je l'ai trouvé utile plusieurs fois dans la passée.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



1 2