Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Template et spécialisation partiel d'une méthode...

5 réponses
Avatar
Etienne
Bonjour,

Je vous montre ce que j'aurais aim=E9 faire :

#include <iostream>
#include <string>

using namespace std;

template <class T, bool b>
class Toto
{
public:
Toto(const T& t) : _t (t)
{
}

void tata(void);

private:
T _t;
};

template <class T, bool b>
void Toto<T, false>::tata(void)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T, bool b>
void Toto<T, true>::tata(void)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

int main(void)
{
Toto<int, true> t1 (5);
Toto<int, false> t2 (6);

t1.tata();
t2.tata();

return 0;
}

Mais g++ n'aime pas mon code :
$ g++ t.cc
t=2Ecc:22: error: no `void Toto<T, false>::tata()' member function
declared in
class `Toto<T, false>'
t=2Ecc:22: error: template definition of non-template `void Toto<T,
false>::tata()'
t=2Ecc:28: error: no `void Toto<T, true>::tata()' member function
declared in
class `Toto<T, true>'
t=2Ecc:28: error: template definition of non-template `void Toto<T,
true>::tata()'

Pour r=E9soudre ce probl=E8me j'ai du utilis=E9 la sp=E9cialisation partiel
:
#include <iostream>
#include <string>

using namespace std;

template <class T, bool b>
class Toto
{
public:
Toto(const T& t) : _t (t)
{
}

void tata(void);

private:
T _t;
};

template <class T>
class Toto<T, true>
{
public:
Toto(const T& t) : _t (t)
{
}

void tata(void);

private:
T _t;
};

template <class T, bool b>
void Toto<T, b>::tata(void)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T>
void Toto<T, true>::tata(void)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

int main(void)
{
Toto<int, true> t1 (5);
Toto<int, false> t2 (6);

t1.tata();
t2.tata();

return 0;
}


Cela compile... mais je n'aime pas trop car il y a redondance de code.
Pour eviter cette duplication de code j'ai utilis=E9 les macro :

#include <iostream>
#include <string>

using namespace std;

# define BODY\
{ \
public: \
Toto(const T& t) : _t (t) \
{ \
} \
\
void tata(void); \
\
private: \
T _t; \
}


template <class T, bool b> class Toto BODY;
template <class T> class Toto<T, true> BODY;

#undef BODY

template <class T, bool b>
void Toto<T, b>::tata(void)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T>
void Toto<T, true>::tata(void)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

int main(void)
{
Toto<int, true> t1 (5);
Toto<int, false> t2 (6);

t1.tata();
t2.tata();

return 0;
}

D'ou ma question : existe t-il une solution a mon probleme sans
duplication de code et sans macro ?

Etienne

5 réponses

Avatar
kanze
Etienne wrote:

Je vous montre ce que j'aurais aimé faire :

#include <iostream>
#include <string>

using namespace std;

template <class T, bool b>
class Toto
{
public:
Toto(const T& t) : _t (t)
{
}

void tata(void);

private:
T _t;
};

template <class T, bool b>
void Toto<T, false>::tata(void)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T, bool b>
void Toto<T, true>::tata(void)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

int main(void)
{
Toto<int, true> t1 (5);
Toto<int, false> t2 (6);

t1.tata();
t2.tata();

return 0;
}

Mais g++ n'aime pas mon code :
$ g++ t.cc
t.cc:22: error: no `void Toto<T, false>::tata()' member function
declared in
class `Toto<T, false>'
t.cc:22: error: template definition of non-template `void Toto<T,
false>::tata()'
t.cc:28: error: no `void Toto<T, true>::tata()' member function
declared in
class `Toto<T, true>'
t.cc:28: error: template definition of non-template `void Toto<T,
true>::tata()'

Pour résoudre ce problème j'ai du utilisé la spécialisation
partiel :


C'est en fait ce que tu veux, non ? Seulement, tu le veux sur la
fonction, et non sur la classe. Or, si j'ai bien compris, pour
les fonctions, on n'a pas de spécialisation partielle ; on
exploite plutôt la résolution du surcharge. Quelque chose du
genre :

template< bool b >
struct Discriminator {} ;

//...

template <class T, bool b>
class Toto
{
public:
void tata()
{
doTata( Discriminator< b >() ) ;
}
private:
void doTata( Discriminator< true > ) ;
void doTata( Discriminator< false > ) ;
} ;

template <class T, bool b>
void Toto<T, b>::doTata(Discriminator< false >)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T, bool b>
void Toto<T, b>::doTata(Discriminator< true>)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

Sinon, dans des cas aussi simple qu'ici, Tu peux mettre le code
dans le discriminateur même, et appeler :
Discriminator< b >::tata() ;
ou
Discriminator< b >().tata() ;
dans Toto<>::tata().

--
James Kanze GABI Software
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

Avatar
Etienne
Merci

Etienne
Avatar
gbaudin
"kanze" a écrit dans le message de news:

Etienne wrote:

Je vous montre ce que j'aurais aimé faire :

#include <iostream>
#include <string>

using namespace std;

template <class T, bool b>
class Toto
{
public:
Toto(const T& t) : _t (t)
{
}

void tata(void);

private:
T _t;
};

template <class T, bool b>
void Toto<T, false>::tata(void)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T, bool b>
void Toto<T, true>::tata(void)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

int main(void)
{
Toto<int, true> t1 (5);
Toto<int, false> t2 (6);

t1.tata();
t2.tata();

return 0;
}

Mais g++ n'aime pas mon code :
$ g++ t.cc
t.cc:22: error: no `void Toto<T, false>::tata()' member function
declared in
class `Toto<T, false>'
t.cc:22: error: template definition of non-template `void Toto<T,
false>::tata()'
t.cc:28: error: no `void Toto<T, true>::tata()' member function
declared in
class `Toto<T, true>'
t.cc:28: error: template definition of non-template `void Toto<T,
true>::tata()'

Pour résoudre ce problème j'ai du utilisé la spécialisation
partiel :


C'est en fait ce que tu veux, non ? Seulement, tu le veux sur la
fonction, et non sur la classe. Or, si j'ai bien compris, pour
les fonctions, on n'a pas de spécialisation partielle ; on
exploite plutôt la résolution du surcharge. Quelque chose du
genre :

template< bool b >
struct Discriminator {} ;

//...

template <class T, bool b>
class Toto
{
public:
void tata()
{
doTata( Discriminator< b >() ) ;
}
private:
void doTata( Discriminator< true > ) ;
void doTata( Discriminator< false > ) ;
} ;

template <class T, bool b>
void Toto<T, b>::doTata(Discriminator< false >)
{
cout << "void Toto<T, false>::tata(void)" << endl;
}

template <class T, bool b>
void Toto<T, b>::doTata(Discriminator< true>)
{
cout << "void Toto<T, true>::tata(void)" << endl;
}

Sinon, dans des cas aussi simple qu'ici, Tu peux mettre le code
dans le discriminateur même, et appeler :
Discriminator< b >::tata() ;
ou
Discriminator< b >().tata() ;
dans Toto<>::tata().

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung



Bonjour,
j'ai a peu pret une question similaire sauf que c'est sur la specialisation
d'une fonction membre d'une classe.
je ne sais pas si on peut faire ce genre de chose :
( j'utilise VC++ 6 )


dans un .h
class A
{
A();
~A()

void methode();

template < long T>
void autre_methode( ... );
};


donc dans le cpp

A::A()
{
}

A::~A()
{
}

void A::methode()
{
...
}

template <long T>
void A::autre_methode( ... )
{
....
} // Ceci est accepté par le
compilateur, mais je n'ai pas teste son fonctionnement ...

// si j'en veux une specialisation, comment je dois la declarer ?

template<>
void A::autre_methode<SPECIALISATION>( ... ) // fatal error
C1001: INTERNAL COMPILER ERROR
{
...
}

ou

template <>
void A<SPECIALISATION>::autre_methode( ... ) // syntax error :
missing ';' before '<'
{
...
}

Est ce que c'est faisable ???
merci.













9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
James Kanze
gbaudin wrote:
"kanze" a écrit dans le message de news:



[...]
j'ai a peu pret une question similaire sauf que c'est sur la
specialisation d'une fonction membre d'une classe.


C'était l'exemple même. Il voulait en fait une spécialisation partielle
d'une fonction. Ça n'existe pas : c'est la spécialisation
partielle pour les classes, et le surcharge pour les fonctions.

je ne sais pas si on peut faire ce genre de chose : (
j'utilise VC++ 6 )


dans un .h
class A
{
A();
~A()


void methode();


template < long T>
void autre_methode( ... );
};


donc dans le cpp


A::A()
{
}


A::~A()
{
}


void A::methode()
{
...
}


template <long T>
void A::autre_methode( ... )
{
....
} // Ceci est accepté par le
compilateur, mais je n'ai pas teste son fonctionnement ...


// si j'en veux une specialisation, comment je dois la declarer ?


template<>
void A::autre_methode<SPECIALISATION>( ... ) // fatal error
C1001: INTERNAL COMPILER ERROR
{
...
}


A priori, c'est correct. (Et le compilateur t'as dit qu'il y a
une erreur chez lui, non dans ton code.) Dans le cas d'une
fonction libre, en tout cas, il y a même un exemple à peu près
identique dans la norme :
template<> void sort<char*>(Array<char*>& v) { /*...*/ }
G++ accepte aussi la même chose quand la fonction est un membre.

Note que si le type figure parmi les paramètres, tu peux aussi
écrire simplement :
template<>
void A::autre_methode( ... ) { ... }
avec le paramètre explicité.

ou


template <>
void A<SPECIALISATION>::autre_methode( ... ) // syntax error :
missing ';' before '<'
{
...
}


Là, c'est clair. Tu as démandé une spécialisation d'une fonction
non-templatéee dans une classe templatée. Ou plutôt... Du fait
que A n'est pas un template, le '<' qui en suit le nom signifie
l'opérateur « inférieur à ». Ce qui n'est pas légal dans ce
contexte.

Est ce que c'est faisable ???


Le code suivant marche avec g++. Je dirais qu'il y a une erreur
dans ton compilateur. (En général, si tu vois le message
« internal compiler error », ou quelque chose du genre, tu peux
partir du principe qu'il y a une erreur dans le compilateur.
Peut-être aussi dans ton code aussi, mais sûrement dans le
compilateur.)

#include <iostream>
#include <ostream>

struct A
{
template< typename T >
void f()
{
std::cout << "A::f() générique" << std::endl ;
}
template< typename T >
void g( T const& )
{
std::cout << "A::g() générique" << std::endl ;
}
} ;

template<>
void A::f< int >()
{
std::cout << "A::f() spécialisée" << std::endl ;
}

template<>
void A::g( int const& )
{
std::cout << "A::g() spécialisée" << std::endl ;
}

int
main()
{
A a ;
a.f< double >() ;
a.f< int >() ;
a.g( 1.3 ) ;
a.g( 2 ) ;
return 0 ;
}

Faute d'autre chose, pour avancer, donne un paramètre bidon
(avec une valeur par défaut) à la fonction, et utiliser le
format qui m'a servi pour g(), ci-dessus, pour la
spécialisation. Avec un peu de chance, tu contourneras l'erreur
du compilateur.

--
James Kanze
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


Avatar
gbaudin
"James Kanze" a écrit dans le message de news:
e447if$poh$
gbaudin wrote:
"kanze" a écrit dans le message de news:



[...]
j'ai a peu pret une question similaire sauf que c'est sur la
specialisation d'une fonction membre d'une classe.


C'était l'exemple même. Il voulait en fait une spécialisation partielle
d'une fonction. Ça n'existe pas : c'est la spécialisation
partielle pour les classes, et le surcharge pour les fonctions.

je ne sais pas si on peut faire ce genre de chose : (
j'utilise VC++ 6 )

dans un .h
class A
{
A();
~A()

void methode();

template < long T>
void autre_methode( ... );
};

donc dans le cpp

A::A()
{
}

A::~A()
{
}

void A::methode()
{
...
}

template <long T>
void A::autre_methode( ... )
{
....
} // Ceci est accepté par le
compilateur, mais je n'ai pas teste son fonctionnement ...

// si j'en veux une specialisation, comment je dois la declarer ?

template<>
void A::autre_methode<SPECIALISATION>( ... ) // fatal error
C1001: INTERNAL COMPILER ERROR
{
...
}


A priori, c'est correct. (Et le compilateur t'as dit qu'il y a
une erreur chez lui, non dans ton code.) Dans le cas d'une
fonction libre, en tout cas, il y a même un exemple à peu près
identique dans la norme :
template<> void sort<char*>(Array<char*>& v) { /*...*/ }
G++ accepte aussi la même chose quand la fonction est un membre.

Note que si le type figure parmi les paramètres, tu peux aussi
écrire simplement :
template<>
void A::autre_methode( ... ) { ... }
avec le paramètre explicité.

ou

template <>
void A<SPECIALISATION>::autre_methode( ... ) // syntax error :
missing ';' before '<'
{
...
}


Là, c'est clair. Tu as démandé une spécialisation d'une fonction
non-templatéee dans une classe templatée. Ou plutôt... Du fait
que A n'est pas un template, le '<' qui en suit le nom signifie
l'opérateur « inférieur à ». Ce qui n'est pas légal dans ce
contexte.

Est ce que c'est faisable ???


Le code suivant marche avec g++. Je dirais qu'il y a une erreur
dans ton compilateur. (En général, si tu vois le message
« internal compiler error », ou quelque chose du genre, tu peux
partir du principe qu'il y a une erreur dans le compilateur.
Peut-être aussi dans ton code aussi, mais sûrement dans le
compilateur.)

#include <iostream>
#include <ostream>

struct A
{
template< typename T >
void f()
{
std::cout << "A::f() générique" << std::endl ;
}
template< typename T >
void g( T const& )
{
std::cout << "A::g() générique" << std::endl ;
}
} ;

template<>
void A::f< int >()
{
std::cout << "A::f() spécialisée" << std::endl ;
}

template<>
void A::g( int const& )
{
std::cout << "A::g() spécialisée" << std::endl ;
}

int
main()
{
A a ;
a.f< double >() ;
a.f< int >() ;
a.g( 1.3 ) ;
a.g( 2 ) ;
return 0 ;
}

Faute d'autre chose, pour avancer, donne un paramètre bidon
(avec une valeur par défaut) à la fonction, et utiliser le
format qui m'a servi pour g(), ci-dessus, pour la
spécialisation. Avec un peu de chance, tu contourneras l'erreur
du compilateur.

--
James Kanze
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



----- Original Message -----
From: "James Kanze"
Newsgroups: fr.comp.lang.c++
Sent: Saturday, May 13, 2006 11:12 AM
Subject: Re: Template et spécialisation partiel d'une méthode...


gbaudin wrote:
"kanze" a écrit dans le message de news:



[...]
j'ai a peu pret une question similaire sauf que c'est sur la
specialisation d'une fonction membre d'une classe.


C'était l'exemple même. Il voulait en fait une spécialisation partielle
d'une fonction. Ça n'existe pas : c'est la spécialisation
partielle pour les classes, et le surcharge pour les fonctions.

je ne sais pas si on peut faire ce genre de chose : (
j'utilise VC++ 6 )

dans un .h
class A
{
A();
~A()

void methode();

template < long T>
void autre_methode( ... );
};

donc dans le cpp

A::A()
{
}

A::~A()
{
}

void A::methode()
{
...
}

template <long T>
void A::autre_methode( ... )
{
....
} // Ceci est accepté par le
compilateur, mais je n'ai pas teste son fonctionnement ...

// si j'en veux une specialisation, comment je dois la declarer ?

template<>
void A::autre_methode<SPECIALISATION>( ... ) // fatal error
C1001: INTERNAL COMPILER ERROR
{
...
}


A priori, c'est correct. (Et le compilateur t'as dit qu'il y a
une erreur chez lui, non dans ton code.) Dans le cas d'une
fonction libre, en tout cas, il y a même un exemple à peu près
identique dans la norme :
template<> void sort<char*>(Array<char*>& v) { /*...*/ }
G++ accepte aussi la même chose quand la fonction est un membre.

Note que si le type figure parmi les paramètres, tu peux aussi
écrire simplement :
template<>
void A::autre_methode( ... ) { ... }
avec le paramètre explicité.

ou

template <>
void A<SPECIALISATION>::autre_methode( ... ) // syntax error :
missing ';' before '<'
{
...
}


Là, c'est clair. Tu as démandé une spécialisation d'une fonction
non-templatéee dans une classe templatée. Ou plutôt... Du fait
que A n'est pas un template, le '<' qui en suit le nom signifie
l'opérateur « inférieur à ». Ce qui n'est pas légal dans ce
contexte.

Est ce que c'est faisable ???


Le code suivant marche avec g++. Je dirais qu'il y a une erreur
dans ton compilateur. (En général, si tu vois le message
« internal compiler error », ou quelque chose du genre, tu peux
partir du principe qu'il y a une erreur dans le compilateur.
Peut-être aussi dans ton code aussi, mais sûrement dans le
compilateur.)

#include <iostream>
#include <ostream>

struct A
{
template< typename T >
void f()
{
std::cout << "A::f() générique" << std::endl ;
}
template< typename T >
void g( T const& )
{
std::cout << "A::g() générique" << std::endl ;
}
} ;

template<>
void A::f< int >()
{
std::cout << "A::f() spécialisée" << std::endl ;
}

template<>
void A::g( int const& )
{
std::cout << "A::g() spécialisée" << std::endl ;
}

int
main()
{
A a ;
a.f< double >() ;
a.f< int >() ;
a.g( 1.3 ) ;
a.g( 2 ) ;
return 0 ;
}

Faute d'autre chose, pour avancer, donne un paramètre bidon
(avec une valeur par défaut) à la fonction, et utiliser le
format qui m'a servi pour g(), ci-dessus, pour la
spécialisation. Avec un peu de chance, tu contourneras l'erreur
du compilateur.

--
James Kanze
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


effectivement, j'ai compilé et debuggé cet exemple avec g++ ...

sous VC++ 6 ca me donne le resultat que j'ai deja affiche plus haut :
Compiling...
main.cpp
c:testtestmain.cpp(21) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 1794)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more
information
Error executing cl.exe.

Test.exe - 1 error(s), 0 warning(s)

Avec VC++ 7, au moins il n'y a pas d'erreur du compilateur, mais il refuse
la surcharge
------ Rebuild All started: Project: Test, Configuration: Debug Win32 ------
Deleting intermediate files and output files for project 'Test',
configuration 'Debug|Win32'.
Compiling...
main.cpp
c:testTestmain.cpp(22) : error C2511: 'void A::f(void)' : overloaded
member function not found in 'A'
c:testTestmain.cpp(6) : see declaration of 'A'
c:testTestmain.cpp(28) : error C2511: 'void A::g(const int &)' :
overloaded member function not found in 'A'
c:testTestmain.cpp(6) : see declaration of 'A'
Build Time 0:00
Build log was saved at "file://c:testTestDebugBuildLog.htm"
Test - 2 error(s), 0 warning(s)


finalement avec VC++ 7.1 ( .Net 2003 ), ca compile et ca marche ... du coup
je n'ai pas testé avec VC++ 2005 mais a priori ca devrait fonctionner
egalement ...

voila si ces resultats interessent quelques personnes sur ces compilos ...

c'est quand même bien dommage qu'il n'y a pas de correctif sur les anciennes
versions ...

En fait je voulais utiliser ce type de syntaxe pour ne pas gerer d'enormes
switch dans le code ( a tort ou a raison ? ) mais utiliser une fonction
generale qui retourne une exception et des specialisations pour traiter les
cas particuliers ... Bon bein syntaxe "switch" power on en attendant :))

merci pour l'exemple car je doutais quand même que la syntaxe soit valide !