OVH Cloud OVH Cloud

Pb avec for_each

5 réponses
Avatar
amerio
J'utilise le petit code suivant pour formater du HTML.
tag_br est un simple functor qui remplace les \n par <BR>\n

struct tag_br
{
void operator()(char c)
{
if (c=='\n') str += "<BR>\n";
else str += c;
}
std::string str;
};

void osdinfoVisitorHtml::visitstring(std::string const& str)
{
tag_br br;
br.str += "<P>";
for_each(str.begin(), str.end(), br);
br.str += "</P>";
m_file << br.str;
}

Et bien, si je passe la chaine "toto\n"
je devrais avoir en sortie : <P>toto<BR></P>
Et bien non, sur VC7.1, en debug, j'ai <P></P>
Ce qui me trouble, c'est qu'en debug pas a pas, br.str est correctement remplie !
Cad que br.str == <P>toto<BR> juste avant de quitter le for_each.
C'est *en sortie* du for_each que le contenu est perdu, comme si "le curseur" n'avait pas
avancé dans la string.

Donc : bug a MS ou bug a moi ? Qu'est ce qui m'a echapper, sinon ?
(au passage, si vous avez un oneliner pour faire ca, je prend)

5 réponses

Avatar
Patrick Mézard
"amerio" a écrit dans le message de
news:K%orb.280469$
J'utilise le petit code suivant pour formater du HTML.
tag_br est un simple functor qui remplace les n par <BR>n

struct tag_br
{
void operator()(char c)
{
if (c=='n') str += "<BR>n";
else str += c;
}
std::string str;
};

void osdinfoVisitorHtml::visitstring(std::string const& str)
{
tag_br br;
br.str += "<P>";
for_each(str.begin(), str.end(), br);
br.str += "</P>";
m_file << br.str;
}

Et bien, si je passe la chaine "toton"
je devrais avoir en sortie : <P>toto<BR></P>
Et bien non, sur VC7.1, en debug, j'ai <P></P>
Ce qui me trouble, c'est qu'en debug pas a pas, br.str est correctement
remplie !

Cad que br.str == <P>toto<BR> juste avant de quitter le for_each.
C'est *en sortie* du for_each que le contenu est perdu, comme si "le
curseur" n'avait pas

avancé dans la string.


for_each prend son dernier opérande par copie et le renvoie par copie.
Essaie :

void osdinfoVisitorHtml::visitstring(std::string const& str)
{
tag_br br;
br.str += "<P>";
br = for_each(str.begin(), str.end(), br);
br.str += "</P>";
m_file << br.str;
}

Patrick Mézard

Avatar
Luc Hermitte
"amerio" wrote in
news:K%orb.280469$:

J'utilise le petit code suivant pour formater du HTML.
tag_br est un simple functor qui remplace les n par <BR>n
[...]


std::transform conviendrait peut-etre mieux, non ?

--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>

Avatar
kanze
"amerio" wrote in message
news:<K%orb.280469$...
J'utilise le petit code suivant pour formater du HTML. tag_br est un
simple functor qui remplace les n par <BR>n

struct tag_br
{
void operator()(char c)
{
if (c=='n') str += "<BR>n";
else str += c;
}
std::string str;
};

void osdinfoVisitorHtml::visitstring(std::string const& str)
{
tag_br br;
br.str += "<P>";
for_each(str.begin(), str.end(), br);
br.str += "</P>";
m_file << br.str;
}

Et bien, si je passe la chaine "toton"
je devrais avoir en sortie : <P>toto<BR></P>
Et bien non, sur VC7.1, en debug, j'ai <P></P>

Ce qui me trouble, c'est qu'en debug pas a pas, br.str est
correctement remplie ! Cad que br.str == <P>toto<BR> juste avant de
quitter le for_each. C'est *en sortie* du for_each que le contenu est
perdu, comme si "le curseur" n'avait pas avancé dans la string.


Certainement pas dans le même tag_br. for_each opère sur une copie de
br, qui est détruite à la sortie de for_each.

Ce qu'il te faut donc, c'est de lui passer un handle au tag_br, et non
le tag_br même. Je verrais plutôt quelque chose du genre :

class PreformattedParagraph
{
public:
PreformattedParagraph() ;

std::string value() const
{
return "<P>" + myText + "</P>" ;
}

PreformattedParagraph&
operator+=( char ch )
{
switch ( ch ) {
case 'n' :
myText += "<BR>" ;
break ;

// D'autres caractères à traiter spécialement...

default :
myText += ch ;
break ;
}
}

private:
std::string myText ;
} ;

PreformattedParagraphAppender
{
public:
PreformattedParagraphAppender( PreformattedParagraph& object )
: myObject( &object )
{
}

void operator()( char ch )
{
*myObject += ch ;
}

private:
PreformattedParagraph*
myObject ;
} ;

Avec alors :

void
visitString( std::string const& source )
{
PreformattedParagraph
para ;
std::for_each( source.begin(), source.end(),
PreformattedParagraphAppender( para ) ) ;
myFile << para.value() ;
}

En passant, je me démande si std::accumulate ne serait pas plutôt la
fonction qui t'intéresse. Ajoute un operator+ :

PreformattedParagraph
operator+( PreformattedParagraph const& lhs,
PreformattedParagraph const& rhs )
{
PreformattedParagraph
result( lhs ) ;
result += rhs ;
return result ;
}

Et ça donne :

void
visitString( std::string const& source )
{
myFile << std::accumulate( source.begin(), source.end(),
PreformattedParagraph() ).value() ;
}

--
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
Ce qui me trouble, c'est qu'en debug pas a pas, br.str est
correctement remplie ! Cad que br.str == <P>toto<BR> juste avant de
quitter le for_each. C'est *en sortie* du for_each que le contenu est
perdu, comme si "le curseur" n'avait pas avancé dans la string.


Certainement pas dans le même tag_br. for_each opère sur une copie de
br, qui est détruite à la sortie de for_each.


Oui, en effet, j'avais "survolé" de trop haut cet aspect de for_each.
Merci !
(au passage, juste pour ma culture perso : y-a-t-il une raison à ce passage par valeur ?
je veux dire, au niveau "choix de conception")

Ce qu'il te faut donc, c'est de lui passer un handle au tag_br, et non
le tag_br même. Je verrais plutôt quelque chose du genre :
[snip]


Et beh... Oui, c'est sur, pour un code "industriel" je ferais peut etre comme ca, si le
besoin d'extensibilité etait là.
Mais j'avais plutot demandé un "one-liner" ;-)
Merci bcp qd même pour le "how-to", ca me servira plus tard !
Dans mon cas précis (remplacement multiples dans une chaine), boost::regex::regex_merge
est plus lisible.


Avatar
Gabriel Dos Reis
"amerio" writes:

| >> Ce qui me trouble, c'est qu'en debug pas a pas, br.str est
| >> correctement remplie ! Cad que br.str == <P>toto<BR> juste avant de
| >> quitter le for_each. C'est *en sortie* du for_each que le contenu est
| >> perdu, comme si "le curseur" n'avait pas avancé dans la string.
| >
| > Certainement pas dans le même tag_br. for_each opère sur une copie de
| > br, qui est détruite à la sortie de for_each.
|
| Oui, en effet, j'avais "survolé" de trop haut cet aspect de for_each.
| Merci !
| (au passage, juste pour ma culture perso : y-a-t-il une raison à ce
| passage par valeur ? je veux dire, au niveau "choix de conception")

cohérence avec la STL qui utilise partout une sémantique valeur.

-- Gaby