 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Michaël Delva Guest
|
Posted: Tue Aug 10, 2004 5:13 pm Post subject: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 7:27 am Post subject: Re: Problème de template |
|
|
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
|
|
| Back to top |
|
 |
Arnaud Debaene Guest
|
Posted: Wed Aug 11, 2004 8:06 am Post subject: Re: Problème de template |
|
|
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 </standard disclaimer>
Arnaud
|
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Wed Aug 11, 2004 9:39 am Post subject: Re: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 9:47 am Post subject: Re: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 10:14 am Post subject: Re: Problème de template |
|
|
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
|
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
|
Posted: Wed Aug 11, 2004 11:00 am Post subject: Re: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 11:13 am Post subject: Re: Problème de template |
|
|
| 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
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
|
Posted: Wed Aug 11, 2004 11:21 am Post subject: Re: Problème de template |
|
|
Michaël Delva wrote:
| Quote: |
Ton code marche parfaitement bien
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
|
Posted: Wed Aug 11, 2004 11:24 am Post subject: Re: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 11:36 am Post subject: Re: Problème de template |
|
|
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
|
Posted: Wed Aug 11, 2004 1:22 pm Post subject: Re: Problème de template |
|
|
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
|
Posted: Thu Aug 12, 2004 7:52 am Post subject: Re: Problème de template |
|
|
"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
|
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
|
Posted: Thu Aug 12, 2004 10:29 am Post subject: Re: Problème de template |
|
|
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 |
|
 |
|
|
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
|
|