OVH Cloud OVH Cloud

[débutant] surcharge de template

5 réponses
Avatar
AG
Bonjour, voici mon test qui ne fonctionne pas :

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

template <class C> std::string Serialize(std::string id, C & value)
{
std::ostringstream buff;

buff << "[" << id << "] = " << value;

return buff.str();
}

template <class C> std::string Serialize(std::string id, std::vector<C>
& value)
{
std::ostringstream buff;

buff << "[" << id << "] =";

for(std::vector<C>::iterator i=value.begin();i!=value.end();i++)
{
buff << " " << *i;
}

return buff.str();
}

int main()
{
std::string a;
int b = 12;
std::vector<int> c;

c.push_back(1);
c.push_back(2);
c.push_back(3);

a = Serialize("coucou",c);
std::cout << a;

a = Serialize("coucou",b);
std::cout << a;

return 0;
}

le message d'erreur m'indique qu'il est impossible de choisir quelle
fonction utiliser pour Serialize("coucou",c)

ce que je peux comprendre.... Mais je ne vois pas la solution. un indice ?

AG.

5 réponses

Avatar
xavier
AG a dit le 16/03/2005 00:51:
Bonjour, voici mon test qui ne fonctionne pas :

for(std::vector<C>::iterator i=value.begin();i!=value.end();i++)


! for(typename std::vector<C>::iterator i = value.begin();
! i != value.end(); i++)

est la forme correcte.

le message d'erreur m'indique qu'il est impossible de choisir quelle
fonction utiliser pour Serialize("coucou",c)


Il me semble bien que, à part le problème indiqué ci-dessus, le reste du
programme n'a pas d'erreur et que le compilateur devrait pouvoir
déterminer quel template utiliser. Comeau compile ton test sans problème.

ce que je peux comprendre.... Mais je ne vois pas la solution. un indice ?


Ce que tu fais ici est une surcharge de fonction template, comme tu l'as
indiqué. Une autre solution est de faire une spécialisation de classe :

! // classe generique
! template <typename T>
! struct Serializer {
! static std::string Serialize(std::string const & id,
! T const & value) {
! std::ostringstream oss;
! oss << "[" << id << "] = " << value;
! return oss.str();
! }
! };
!
! // Specialisation partielle pour les std::vector<T>
! template <typename T>
! struct Serializer<std::vector<T> > {
! static std::string Serialize(std::string const & id,
! std::vector<T> const & value) {
! std::ostringstream oss;
! oss << "[" << id << "] = ";
! copy(value.begin(), value.end(),
! std::ostream_iterator<T>(oss, " "));
! return oss.str();
! }
! };
!
! // Fonction d'aide pour eviter de specifier quel template utiliser
! template <typename T>
! inline std::string Serialize(std::string const & id,
! T const & value) {
! return Serializer<T>::Serialize(id, value);
! }

Cette solution, utiliser une classe template composée de fonction
statique est appelée "trait", comme par exemple std::char_traits<>

http://www.sgi.com/tech/stl/character_traits.html

Cependant, si ton compilateur ne supporte pas correctement la surchage
de fonction template, il me semble peu probable qu'il supporte
correctement la spécialisation partielle.

xavier

Avatar
Falk Tannhäuser
AG wrote:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

template <class C> std::string Serialize(std::string id, C & value)


Même si cela n'a rien à voir avec ton problème :
Je mettrais ici
template<class C> std::string Serialize(std::string id, C const& value )
car la fonction n'est pas censée modifier la valeur passée.

{
std::ostringstream buff;
buff << "[" << id << "] = " << value;
return buff.str();
}

template <class C> std::string Serialize(std::string id, std::vector<C> & value)


Pareil : ..., std::vector<C> const& value)

{
std::ostringstream buff;
buff << "[" << id << "] =";

for(std::vector<C>::iterator i=value.begin();i!=value.end();i++ )


Là, il te manque un "typename" car le typedef "iterator" imbriqué dan s std::vector
dépend du paramètre du template. Puis, si tu passes le vecteur en "co nst", il te
faudra utiliser "const_iterator", ce qui donne :
for(typename std::vector<C>::const_iterator i=value.begin(); i!=va lue.end(); ++i)

{
buff << " " << *i;
}

return buff.str();
}

int main()
{
std::string a;
int b = 12;
std::vector<int> c;

c.push_back(1);
c.push_back(2);
c.push_back(3);

a = Serialize("coucou",c);
std::cout << a;

a = Serialize("coucou",b);
std::cout << a;

return 0;
}

le message d'erreur m'indique qu'il est impossible de choisir quelle
fonction utiliser pour Serialize("coucou",c)
ce que je peux comprendre.... Mais je ne vois pas la solution. un indic e ?


Es-tu sûr que le problème est là ? Une fois le "typename" ajouté, ça
devrait compiler (et ça le fait chez moi) ! Après il manque peut-êt re
encore des std::cout << 'n' quelque part pour faire plus beau...

Falk

Avatar
AG
Falk Tannhäuser wrote:

AG wrote:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

template <class C> std::string Serialize(std::string id, C & value)



Même si cela n'a rien à voir avec ton problème :
Je mettrais ici
template<class C> std::string Serialize(std::string id, C const& value)
car la fonction n'est pas censée modifier la valeur passée.
Le const m'a toujours un peu effrayé. ça n'a pas l'air trés simple. Mais

c'est promis, je m'y met rapidement, comme on me l'a déjà conseillé ici.



{
std::ostringstream buff;
buff << "[" << id << "] = " << value;
return buff.str();
}

template <class C> std::string Serialize(std::string id,
std::vector<C>& value)



Pareil : ..., std::vector<C> const& value)

{
std::ostringstream buff;
buff << "[" << id << "] =";

for(std::vector<C>::iterator i=value.begin();i!=value.end();i++)



Là, il te manque un "typename" car le typedef "iterator" imbriqué dans
std::vector
dépend du paramètre du template.
ok, je ne savais pas. J'aurais du lire mon chapitre template en entier.


Puis, si tu passes le vecteur en
"const", il te
faudra utiliser "const_iterator", ce qui donne :
for(typename std::vector<C>::const_iterator i=value.begin();
i!=value.end(); ++i)

{
buff << " " << *i;
}

return buff.str();
}

int main()
{
std::string a;
int b = 12;
std::vector<int> c;
c.push_back(1);
c.push_back(2);
c.push_back(3);

a = Serialize("coucou",c);
std::cout << a;

a = Serialize("coucou",b);
std::cout << a;

return 0;
}

le message d'erreur m'indique qu'il est impossible de choisir quelle
fonction utiliser pour Serialize("coucou",c)
ce que je peux comprendre.... Mais je ne vois pas la solution. un
indice ?



Es-tu sûr que le problème est là ? Une fois le "typename" ajouté, ça
devrait compiler (et ça le fait chez moi) !
je vais voir. Il est aussi possible que mon compilo ne soit aps à jour.


Après il manque peut-être
encore des std::cout << 'n' quelque part pour faire plus beau...

Falk



Merci.


Avatar
AG
xavier wrote:

AG a dit le 16/03/2005 00:51:

Bonjour, voici mon test qui ne fonctionne pas :



for(std::vector<C>::iterator i=value.begin();i!=value.end();i++)



! for(typename std::vector<C>::iterator i = value.begin();
! i != value.end(); i++)

est la forme correcte.
ok



le message d'erreur m'indique qu'il est impossible de choisir quelle
fonction utiliser pour Serialize("coucou",c)



Il me semble bien que, à part le problème indiqué ci-dessus, le reste du
programme n'a pas d'erreur et que le compilateur devrait pouvoir
déterminer quel template utiliser. Comeau compile ton test sans problème.
ok, c'est peut être mon compilo alors. Je vais voir.


Ce que tu fais ici est une surcharge de fonction template, comme tu l'as
indiqué. Une autre solution est de faire une spécialisation de classe :

! // classe generique
! template <typename T>
! struct Serializer {
! static std::string Serialize(std::string const & id,
! T const & value) {
! std::ostringstream oss;
! oss << "[" << id << "] = " << value;
! return oss.str();
! }
! };
!
! // Specialisation partielle pour les std::vector<T>
! template <typename T>
! struct Serializer<std::vector<T> > {
! static std::string Serialize(std::string const & id,
! std::vector<T> const & value) {
! std::ostringstream oss;
! oss << "[" << id << "] = ";
! copy(value.begin(), value.end(),
! std::ostream_iterator<T>(oss, " "));
! return oss.str();
! }
! };
!
! // Fonction d'aide pour eviter de specifier quel template utiliser
! template <typename T>
! inline std::string Serialize(std::string const & id,
! T const & value) {
! return Serializer<T>::Serialize(id, value);
! }

Cette solution, utiliser une classe template composée de fonction
statique est appelée "trait", comme par exemple std::char_traits<>

http://www.sgi.com/tech/stl/character_traits.html

Cependant, si ton compilateur ne supporte pas correctement la surchage
de fonction template, il me semble peu probable qu'il supporte
correctement la spécialisation partielle.

xavier
Merci Xavier pour cet exemple. J'avoue être un peu noyé par les

possibilités d'écrire le moindre truc. J'avais certe vu les
spécialisations, mais je pense qu'il est plus raisonnable de commencer
par la surcharge de fonction toute simple.

Si déjà j'arrivais à utiliser les algorithm comme par exemple :

! copy(value.begin(), value.end(),
! std::ostream_iterator<T>(oss, " "));


dont je soupçonnais l'existence, mais qui m'aurait pris bien trop de
temps pour l'écrire.


Avatar
Fabien LE LEZ
On Wed, 16 Mar 2005 11:24:29 +0100, AG :

Le const m'a toujours un peu effrayé.


Faut pas. C'est justement quand il n'y a pas de const que ça devient
compliqué, parce que n'importe qui peut modifier l'objet.

int const machin= 5;
// "machin" vaudra 5 dans toutes les lignes suivantes, pas de souci

int truc= 5;
// "truc" vaut 5 au début, mais peut changer de valeur ici ou là


--
;-)