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 

Problème de template
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Michaël Delva
Guest





PostPosted: Tue Aug 10, 2004 5:13 pm    Post subject: Problème de template Reply with quote



Salut à tous,

J'ai créé une fonction qui me permet de remplir un vecteur par les
différents éléments d'une chaine std::string:

void __fastcall Tokenize(const std::string & chaine, std::vector<int> &
tokens, const std::string & delimiters)
{
tokens.clear();

std::string::size_type start=0, end;

while((start = chaine.find_first_not_of(delimiters, start)) !=
std::string::npos)
{
end = chaine.find_first_of(delimiters, start);
tokens.push_back(StrToInt(chaine.substr(start, end-start).c_str
()));
start=end;
}
}


void __fastcall Tokenize(const std::string & chaine, std::vector
<std::string> & tokens, const std::string & delimiters)
{
tokens.clear();

std::string::size_type start=0, end;

while((start = chaine.find_first_not_of(delimiters, start)) !=
std::string::npos)
{
end = chaine.find_first_of(delimiters, start);
tokens.push_back(chaine.substr(start, end-start).c_str());
start=end;
}
}

Je l'ai surchargé pour pouvoir remplir un vector<int> ou bien un vector
<std::string>

Mais là je voudrais la même fonction pour un vector<unsigned int>, et je me
dis que plutôt que de refaire une troisième fonction identique, je pourrais
utiliser les templates.

Seulement je sais pas faire :(

Comment je peux faire ça?

Merci d'avance
Back to top
Fabien LE LEZ
Guest





PostPosted: Wed Aug 11, 2004 7:27 am    Post subject: Re: Problème de template Reply with quote



On 10 Aug 2004 17:13:18 GMT, "Michaël Delva"
<michael_delva (AT) i_cant_remember (DOT) com>:

Quote:
Mais là je voudrais la même fonction pour un vector<unsigned int>, et je me
dis que plutôt que de refaire une troisième fonction identique, je pourrais
utiliser les templates.

Yep. Je dirais même plus : tu as déjà deux fonctions qui font la même
chose, il y a donc un problème.

template <class Element> void Tokenize
(const std::string & chaine,
std::vector<Element> & tokens,
const std::string & delimiters)
{
tokens.clear();

std::string::size_type start= 0;

while((start = chaine.find_first_not_of(delimiters, start)) !=
std::string::npos)
{
std::string::size_type
end= chaine.find_first_of(delimiters, start);
Element e;
Convertir (e, chaine.substr(start, end-start));
tokens.push_back (e);
start=end;
/* Note : je n'ai pas changé la boucle car je ne sais pas ce que tu
veux faire exactement */
}
}

void Convertir (int& out, std::string const& s);
void Convertir (unsigned int& out, std::string const& s);

void Convertir (std::string const& out, std::string const& s)
{
out= s;
}




--
;-)

Back to top
Jean-Marc Bourguet
Guest





PostPosted: Wed Aug 11, 2004 7:49 am    Post subject: Re: Problème de template Reply with quote



Fabien LE LEZ <gramster (AT) gramster (DOT) com> writes:

J'ai bien aime ton choix pour l'autre message ou tu donnes la meme
reponse...

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Back to top
Arnaud Debaene
Guest





PostPosted: Wed Aug 11, 2004 8:06 am    Post subject: Re: Problème de template Reply with quote

Michaël Delva wrote:
Quote:
Salut à tous,

J'ai créé une fonction qui me permet de remplir un vecteur par les
différents éléments d'une chaine std::string:

<snip>
Quote:

Je l'ai surchargé pour pouvoir remplir un vector<int> ou bien un
vector <std::string

Mais là je voudrais la même fonction pour un vector je me dis que plutôt que de refaire une troisième fonction identique,
je pourrais utiliser les templates.

Seulement je sais pas faire :(

Comment je peux faire ça?

Commences par analyser ton code existant : tes 2 fonctions sont strictement
identiques à une ligne près :

Quote:
tokens.push_back(StrToInt(chaine.substr(start, end-start).c_str ()));
//version int
tokens.push_back(chaine.substr(start, end-start).c_str()); //version
string


A partir de là, on voit que, pour écrire une version générique de ta
fonction, il va nous falloir un paramètre supplémentaire : un
objet/fonction/truc d'insertion qui prend en entrée un std::string et
recrache en sortie la conversion de cette chaîne en type adapté à ton
conteneur cible.

Appelons cette "chose" StringConverter, et prenons comme convention que
c'est un objet, et que c'est son opérateur () qui doit être appelé pour
faire cette conversion. La version générique de StringConverter s'écrit
ainsi:

template <class T> struct StringConverter
{
inline T operator() (const std::string& s)
{
return s;
}
};
Cette version générique fonctionnera pour n'importe quel type "implicitement
constructible" depuis une std::string, y compris std::string elle-même!

Maintenant, écrivons une spécialisation de notre petite classe de conversion
pour les int :
template<> struct StringConverter<int>
{
inline int operator() (const std::string& s)
{
return StrToInt(s);
}
};

Tu peux écrire d'autres spécialisations de StringConverter pour tous les
types dont tu peux avoir besoin : unsigned int ou n'importe quoi d'autre.

Maintenant, il ne nous reste plus qu'à écrire une version template de ta
fonction Tokenize. Il y a un seul paramètre template : le type du vecteur de
sortie.
template <class OutputType> void __fastcall Tokenize(const std::string &
chaine, std::vector<OutputType> &tokens, const std::string & delimiters)
{
StringConverter<OutputType> converter; //objet qui va être utilisé pour
obtenir la conversion de chaque sous-chaîne en OutputType.
tokens.clear();

std::string::size_type start=0, end;

while((start = chaine.find_first_not_of(delimiters, start)) !=
std::string::npos)
{
end = chaine.find_first_of(delimiters, start);
tokens.push_back(converter(chaine.substr(start, end-start)));
start=end;
}
}

Et voilà! Pour l'appel de cete fonction, tu n'as même pas besoin de
spécifier le paramètre template, il est déduit du type du paramètre "tokens"
:
std::vector<int> mes_tokens;
Tokenize(ma_chaine, mes_tokens, mes_delimiteurs); //appelée avec un
vector<int>, donc OutputType==int.

Notes bien que c'est une solution parmi d'autres, et pas forcément la
meilleure, vu qu'il faut définir une spécialisation de TypeConverter pour
tous les types que tu veux utiliser (il est certainement possible de faire
mieux avec des typetraits), mais c'est une 1ère approche.

<standard disclaimer> Code écrit à la va-vite et non testé, fourni sans
aucune garantie Smile </standard disclaimer>

Arnaud



Back to top
Fabien LE LEZ
Guest





PostPosted: Wed Aug 11, 2004 9:39 am    Post subject: Re: Problème de template Reply with quote

On 11 Aug 2004 09:49:01 +0200, Jean-Marc Bourguet <jm (AT) bourguet (DOT) org>:

Quote:
J'ai bien aime ton choix pour l'autre message ou tu donnes la meme
reponse...

Autre message ? Je sais que j'ai écrit deux fois le même message, mais
c'est parce que le premier a disparu de ma boîte d'envoi (qui garde
pourtant les messages jusqu'à ce que je les efface à la main), et
n'apparaît pas sur mon serveur (news.free.fr). Je ne sais pas du tout
ce qui s'est passé.


--
;-)

Back to top
Jean-Marc Bourguet
Guest





PostPosted: Wed Aug 11, 2004 9:47 am    Post subject: Re: Problème de template Reply with quote

Fabien LE LEZ <gramster (AT) gramster (DOT) com> writes:

Quote:
On 11 Aug 2004 09:49:01 +0200, Jean-Marc Bourguet <jm (AT) bourguet (DOT) org>:

J'ai bien aime ton choix pour l'autre message ou tu donnes la meme
reponse...

Autre message ? Je sais que j'ai écrit deux fois le même message, mais
c'est parce que le premier a disparu de ma boîte d'envoi (qui garde
pourtant les messages jusqu'à ce que je les efface à la main), et
n'apparaît pas sur mon serveur (news.free.fr). Je ne sais pas du tout
ce qui s'est passé.

Je l'ai lu sur news.free.fr, en reponse a un de mes messages ou il est
question de marais et de crocodiles :-)

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Back to top
Fabien LE LEZ
Guest





PostPosted: Wed Aug 11, 2004 10:14 am    Post subject: Re: Problème de template Reply with quote

On 11 Aug 2004 11:47:49 +0200, Jean-Marc Bourguet <jm (AT) bourguet (DOT) org>:

Quote:
Je l'ai lu sur news.free.fr, en reponse a un de mes messages ou il est
question de marais et de crocodiles Smile

Ah, OK !
Je n'avais pas compris que tu parlais de l'autre thread.
Quand tu dis "l'autre message" alors que j'en ai envoyé 30, c'est
difficile de suivre ;-)

Euh... D'ailleurs, de quoi tu parles exactement ? Tu as écrit "Fabien
LE LEZ <gramster (AT) gramster (DOT) com> writes:" mais avec aucune citation.
Message parti trop vite ?




--
;-)

Back to top
Michaël Delva
Guest





PostPosted: Wed Aug 11, 2004 11:00 am    Post subject: Re: Problème de template Reply with quote

Merci à vous deux pour vos réponses et éclaircissements...

Je commence à me rendre compte de la puissance des templates!

Faudra que je m'y interesse sérieusement bientôt!

Encore merci...
Back to top
Michaël Delva
Guest





PostPosted: Wed Aug 11, 2004 11:13 am    Post subject: Re: Problème de template Reply with quote

Quote:
std::vector<int> mes_tokens;
Tokenize(ma_chaine, mes_tokens, mes_delimiteurs); //appelée avec un
vector<int>, donc OutputType==int.

Notes bien que c'est une solution parmi d'autres, et pas forcément la
meilleure, vu qu'il faut définir une spécialisation de TypeConverter
pour tous les types que tu veux utiliser (il est certainement possible
de faire mieux avec des typetraits), mais c'est une 1ère approche.

standard disclaimer> Code écrit à la va-vite et non testé, fourni
sans aucune garantie Smile
Arnaud


Ton code marche parfaitement bien ;)

Et tu parles de typetraits, que je ne connais pas... ça consiste en quoi?

Back to top
Arnaud Debaene
Guest





PostPosted: Wed Aug 11, 2004 11:21 am    Post subject: Re: Problème de template Reply with quote

Michaël Delva wrote:
Quote:

Ton code marche parfaitement bien Wink
Ouf! ;-)

Et tu parles de typetraits, que je ne connais pas... ça consiste en
quoi?

Googlise un peu sur le sujet. L'idée serait par exemple d'avoir une seule
version de StringConverter pour tous les types numériques intégraux (int,
short, long, unsigned ou pas), et de sélectionner cette spécialisation pour
tous ces types en se basant sur un "trait" (ou "tag"si tu préfère) qui
indique que ces types sont efectivement des numériques intégraux.

Arnaud



Back to top
Fabien LE LEZ
Guest





PostPosted: Wed Aug 11, 2004 11:24 am    Post subject: Re: Problème de template Reply with quote

On 11 Aug 2004 11:13:30 GMT, "Michaël Delva"
<michael_delva (AT) i_cant_remember (DOT) com>:

Quote:
Et tu parles de typetraits, que je ne connais pas... ça consiste en quoi?

J'imagine qu'il s'agit des "traits" (je ne sais pas s'il y a un
équivalent en français). Il s'agit de classes dont tous les membres
sont statiques, et qui donne des informations générales (généralement,
sur un type).

Le plus classique est std::numeric_limits<>.

Autre exemple :

class TerminaisonZero
{
static char const caractere_fin= '';
};

class TerminaisonFinLigne
{
static char const caractere_fin= 'n';
};

template <class Trait> class BasicString
{
public:
size_t Longueur()
{
int reponse= 0;
while (data[reponse] != Trait::caractere_fin) ++reponse;
return reponse;
}
};

typedef BasicString<TerminaisonZero> ChaineClassique;
typedef BasicString<TerminaisonFinLigne> ChaineLigne;

"TerminaisonZero" et "TerminaisonFinLigne" sont des traits.


--
;-)

Back to top
Jean-Marc Bourguet
Guest





PostPosted: Wed Aug 11, 2004 11:36 am    Post subject: Re: Problème de template Reply with quote

Fabien LE LEZ <gramster (AT) gramster (DOT) com> writes:

Quote:
On 11 Aug 2004 11:47:49 +0200, Jean-Marc Bourguet <jm (AT) bourguet (DOT) org>:

Je l'ai lu sur news.free.fr, en reponse a un de mes messages ou il est
question de marais et de crocodiles :-)

Ah, OK !
Je n'avais pas compris que tu parlais de l'autre thread.
Quand tu dis "l'autre message" alors que j'en ai envoyé 30, c'est
difficile de suivre ;-)

Euh... D'ailleurs, de quoi tu parles exactement ? Tu as écrit "Fabien
LE LEZ <gramster (AT) gramster (DOT) com> writes:" mais avec aucune citation.
Message parti trop vite ?

Dans l'autre thread, tu donne la solution a ce probleme-ci.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Back to top
Michaël Delva
Guest





PostPosted: Wed Aug 11, 2004 1:22 pm    Post subject: Re: Problème de template Reply with quote

Fabien LE LEZ <gramster (AT) gramster (DOT) com> wrote in
news:juvjh0hs7irhqudt1n4cifv9nlnki4f24t (AT) 4ax (DOT) com:

Quote:
On 11 Aug 2004 11:13:30 GMT, "Michaël Delva"
[email]michael_delva (AT) i_cant_remember (DOT) com[/email]>:

Et tu parles de typetraits, que je ne connais pas... ça consiste en quoi?

J'imagine qu'il s'agit des "traits" (je ne sais pas s'il y a un
équivalent en français). Il s'agit de classes dont tous les membres
sont statiques, et qui donne des informations générales (généralement,
sur un type).

Le plus classique est std::numeric_limits<>.

Autre exemple :

class TerminaisonZero
{
static char const caractere_fin= '';
};

class TerminaisonFinLigne
{
static char const caractere_fin= 'n';
};

template <class Trait> class BasicString
{
public:
size_t Longueur()
{
int reponse= 0;
while (data[reponse] != Trait::caractere_fin) ++reponse;
return reponse;
}
};

typedef BasicString<TerminaisonZero> ChaineClassique;
typedef BasicString<TerminaisonFinLigne> ChaineLigne;

"TerminaisonZero" et "TerminaisonFinLigne" sont des traits.



C'est ce que j'avais vu sur Internet, mais j'avoue ne pas saisir leur
utilité dans mon cas???

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Aug 12, 2004 7:52 am    Post subject: Re: Problème de template Reply with quote

"Arnaud Debaene" <adebaene (AT) club-internet (DOT) fr> wrote


Quote:
Michaël Delva wrote:

J'ai créé une fonction qui me permet de remplir un vecteur par les
différents éléments d'une chaine std::string:

snip

Je l'ai surchargé pour pouvoir remplir un vector<int> ou bien un
vector <std::string

Mais là je voudrais la même fonction pour un vector et je me dis que plutôt que de refaire une troisième fonction
identique, je pourrais utiliser les templates.

Seulement je sais pas faire :(

Comment je peux faire ça?

[...]

Quote:
Tu peux écrire d'autres spécialisations de StringConverter pour tous
les types dont tu peux avoir besoin : unsigned int ou n'importe quoi
d'autre.

Maintenant, il ne nous reste plus qu'à écrire une version template de
ta fonction Tokenize. Il y a un seul paramètre template : le type du
vecteur de sortie.

En plus, même si je ne suis pas pour la généricité à outrance, je crois
que j'écrirais la fonction de façon à utiliser des itérateurs. Et le
convertisseur comme paramètre.

Quote:
template <class OutputType> void __fastcall Tokenize(const std::string &
chaine, std::vector<OutputType> &tokens, const std::string & delimiters)

template< typename OutIter, typename Cvt >
void
Tokenize(
std::string const& source,
OutIter dest,
Cvt convert,
std::string const& delimiters )
{
size_t start = source.find_first_not_of( delimiters ) ;
while ( start != std::string::npos ) {
size_t end
= source.find_first_of( delimiters, start ) ;
*dest ++ = convert( source.substr( start, end ) ;
start = source.find_first_not_of( delimiters, end ) ;
}
}

À l'appel, on passe quelque chose comme std::back_inserter( monVector )
comme paramètre de dest. Et quelque chose comme StringConverter< int >()
comme convert -- on pourrait aussi envisager une fonction qui n'a pas ce
paramètre :

template< typename OutIter >
void
Tokenize(
std::string const& source,
OutIter dest,
std::string const& delimiters )
{
return Tokenize(
source,
dest,
StringConverter< std::iterator_traits< OutIter >::value_type >(),
delimiters ) ;
}

On pourrait aussi envisager passer une paire d'itérateurs comme source.
Dans ce cas-là, on commencera par définir des objets fonctionnels qui
correspondent à find_first_not_of et à find_first_of :

class IsElement
{
public:
IsElement( std::string const& list )
: myList( list )
{
}
bool operator()( char ch ) const
{
return std::find( list.begin(), list.end(), ch ) != list.end() ;
}
private:
std::string myList ;
} ;

La même chose pour IsNotElement, et on pourrait écrire :

template< typename FwdIter, typename OutIter, typename Cvt >
void
Tokenize(
FwdIter begin,
FwdIter end,
OutIter dest,
Cvt convert,
std::string const& delimiter )
{
FwdIter tokenBegin
= std::find_if( begin, end, IsNotElement( delimiter ) ) ;
while ( tokenBegin != end ) {
FwdIter tokenEnd
= std::find_if( tokenBegin, end, IsElement( delimiter ) ) ;
*dest ++ = convert( std::string( tokenBegin, tokenEnd ) ) ;
// à moins que convert prend aussi des itérateurs...
tokenBegin
= std::find_if( tokenEnd, end, IsNotElement( delimiter ) ) ;
}
}

Mais là, je dirais que c'est seulement si Michaël a envie d'expérimenter
avec les concepts de la STL. On n'a rarement besoin d'autant de
généricité.

[...]
Quote:
standard disclaimer> Code écrit à la va-vite et non testé, fourni
sans aucune garantie Smile

De même.

--
James Kanze GABI Software http://www.gabi-soft.fr
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
Michaël Delva
Guest





PostPosted: Thu Aug 12, 2004 10:29 am    Post subject: Re: Problème de template Reply with quote

Je suis réellement impressionné par ce genre de code...

Pas facile à comprendre les templates!! Et dire que tu as du passer 10
minutes à écrire ça!

Merci pour le code, il va être source d'inspiration un jour ou l'autre j'en
suis sûr...
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
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.