Spécialisation des templates

Spécialisation des templates - C++ - Programmation

Marsh Posté le 28-07-2003 à 23:31:46    

l'intéret c'est d'avoir une version générique passe partout, et des versions spécialisées pour certains types, souvent pour permettre des optimisations.
 
par exemple std::swap est muni de spécialisation pour les types de la STL. par exemple: quand on veut permuter 2 std::vector, il serait bête de procéder à plusieurs recopies (c'est à dire le swap de base, avec un variable temporaire) alors qu'on pourrait seulement se contenter de permuter 2 pointeurs (on permute les implémentations)
 
le code parle de lui même, petit exemple clef en main
 

Code :
  1. #include <iostream>
  2. #include <typeinfo>
  3. using namespace std;
  4. class Bar{};
  5. template<class T>
  6. class Foo
  7. {
  8.   T item;
  9. public:
  10.   static void say_hello()
  11.   {
  12.     cout << "Foo " << typeid(T).name() << " générique" << endl;
  13.   }
  14. };
  15. // spécialisation pour un type donné
  16. template<>
  17. class Foo<Bar>
  18. {
  19. public:
  20.   static void say_hello()
  21.   {
  22.     cout << "FooBar" << endl;
  23.   }
  24. };
  25. // spécialisation partielle pour tout type de pointeur
  26. template<class T>
  27. class Foo< T* >
  28. {
  29.   T *item;
  30. public:
  31.   static void say_hello()
  32.   {
  33.     cout << "Foo " << typeid(T).name() << " spécialisé pointeur" << endl;
  34.   }
  35. };
  36. // spécialisation pour les pointeurs de void
  37. template <>
  38. class Foo<void*>
  39. {
  40.   void *item;
  41. public:
  42.   static void say_hello()
  43.   {
  44.     cout << "Foo " << typeid(void).name() << " spécialisé pointeur" << endl;
  45.   }
  46. };
  47. int main()
  48. {
  49.   Foo<int>::say_hello();
  50.   Foo<Bar>::say_hello();
  51.   Foo<bool*>::say_hello();
  52.   Foo<void*>::say_hello();
  53. }


 
 
autre exemple
 

Code :
  1. template<unsigned Dim, typename T>
  2. struct Dot;
  3. template<typename T>
  4. struct Dot<1, T>
  5. {
  6.   static inline T dot(const T *a, const T *b)
  7.   {
  8.     return *a * *b;
  9.   }
  10. };
  11. template<unsigned Dim, typename T>
  12. struct Dot
  13. {
  14.   static inline T dot(const T *a, const T *b)
  15.   {
  16.     return (*a * *b) + Dot<Dim-1, T>::dot(a+1, b+1);
  17.   }
  18. };
  19. template<unsigned Dim, typename T>
  20. inline T dot(const T *a, const T *b)
  21. {
  22.   return Dot<Dim, T>::dot(a, b);
  23. }


 
 
et encore un
 

Code :
  1. template<unsigned m, unsigned n>
  2. struct Ackermann;
  3. template<unsigned n>
  4. struct Ackermann<0, n>
  5. {
  6.   static const unsigned value = n+1;
  7. };
  8. template<unsigned m>
  9. struct Ackermann<m, 0>
  10. {
  11.   static const unsigned value = Ackermann<m-1, 1>::value;
  12. };
  13. template<unsigned m, unsigned n>
  14. struct Ackermann
  15. {
  16.   static const unsigned value = Ackermann<m-1, Ackermann<m, n-1>::value >::value;
  17. };
  18. #include <iostream>
  19. using namespace std;
  20. int main()
  21. {
  22.   cout << Ackermann<3, 4>::value << endl;
  23. }


Message édité par Taz le 05-10-2003 à 14:53:29
Reply

Marsh Posté le 28-07-2003 à 23:31:46   

Reply

Marsh Posté le 06-09-2003 à 01:24:00    

ah, c interressant, je vais travailler ca, merci :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-10-2003 à 13:48:39    

Bonjour tout le monde !
 
J'ai hésite à créer un nouveau topic pour ma question. Taz, si tu penses que ca n'a pas sa place ici vu que je débute avec cà, je créerai un topic.
 
Ma question porte sur la spécialisation partielle des fonctions membres. Par exemple, voici un début de classe Matrix :
 
 

Code :
  1. template<class T, unsigned short i_row, unsigned short i_column>
  2. class CMatrix {    /* Ligne 18 */
  3. public:
  4.  CMatrix() ;
  5.  ~CMatrix() ;
  6.  void fill(const T=0) ;
  7.  void show() const ;
  8.                 T computedet() const ;
  9.  inline bool isSquare() { return (row==column) ; }
  10. private:
  11.  valarray<T> elements; 
  12.  unsigned short row ;
  13.  unsigned short column ;
  14.                 T det ;
  15. };


 
 
Mon but est ici de créer une classe permettant de manipuler des matrices d'un type T, de taille i_row * i_column.
 
J'aimerais pouvoir spécialiser quelques fonctions membres suivant le couple i_row et i_column, pour par exemple la fonction de calcul du déterminant.
 
 
D'abord, je définis une fonction générique :
 

Code :
  1. template<class T, unsigned short i_row, unsigned short i_column>
  2. T CMatrix<T, i_row, i_column>::computedet() const {
  3. // ...
  4. }


 
Je souhaiterais pouvoir spécialiser le calcul de déterminant pour  des valeurs particulières de i_row et i_column, par exemple 2. J'ai essayé cà :
 

Code :
  1. template<class T>
  2. T CMatrix<T, 2, 2>::computedet() const {   /* Ligne 80 */
  3. // ...
  4. }


 
Mais le compilateur me fait comprendre bien gentiment que c'est pas bon :
 


CMatrix.h:80: invalid use of undefined type `class CMatrix<T, 2, 2>'
CMatrix.h:18: declaration of `class CMatrix<T, 2, 2>'
CMatrix.h:80: template definition of non-template `T CMatrix<T, 2, 2>::computedet() const'


 
 
Je m'en suis sorti un temps à l'aide du polymorphisme et de l'héritage en changeant de point de vue, mais j'aimerais comprendre ici pourquoi ca ne fonctionne pas, mon but étant avant tout d'apprendre à manipuler les template :)
 
Merci à vous !


Message édité par Evadream -jbd- le 05-10-2003 à 13:51:26
Reply

Marsh Posté le 05-10-2003 à 14:49:31    

je lis à l'instant ta question : je te trouverais la référence, mais la spécialisation partielle de fonction n'est pas possible, donc idem pour les fonctions membres


Message édité par Taz le 10-02-2004 à 10:43:03
Reply

Marsh Posté le 05-10-2003 à 14:58:13    

Ok, au moins la réponse a le mérite d'être courte. De toute facon il me semblait plus cohérent d'utiliser le polymorphisme et l'héritage pour arriver à mes fins dans ce problème précis.
 
Je suis très intéressé par la référence, si tu tombes dessus :)
 
Encore merci à toi pour ta réponse !

Reply

Marsh Posté le 05-10-2003 à 15:00:59    

non, reste avec les templates. seulement, défni une classe d'aide, avec une unique fonction membre static que tu spécialises autant que tu veux

Reply

Marsh Posté le 05-10-2003 à 15:02:32    

la référence dans cet autre sujet (vers la fin) http://forum.hardware.fr/forum2.ph [...] 218&cat=10

Reply

Marsh Posté le 05-10-2003 à 15:07:42    

Taz a écrit :

non, reste avec les templates. seulement, défni une classe d'aide, avec une unique fonction membre static que tu spécialises autant que tu veux


 
Ok je vais voir dans cette direction ! Et merci pour la référence !
 
@+

Reply

Marsh Posté le 05-10-2003 à 15:14:59    

Evadream -jbd- a écrit :


 
Ok je vais voir dans cette direction ! Et merci pour la référence !
 
@+


 
ou alors tu spécialise toute la classe (template<class T> class CMatrix<T,2,2> ), à toi de voir.


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 05-10-2003 à 15:59:41    

Mmm pourquoi pas, mais ca me semble être une solution de "facilité", non ? Enfin j'ai pas trop de recul vis à vis de ces problèmes, je vais explorer les deux voies :)
 
Merci à toi pour la proposition !


Message édité par Evadream -jbd- le 05-10-2003 à 16:05:57
Reply

Marsh Posté le 05-10-2003 à 15:59:41   

Reply

Marsh Posté le 05-10-2003 à 16:13:14    

ce n'est pas une solution de facilité, c'est une très bonne solution. d'ailleurs ça me fait penser à un truc ...

Reply

Marsh Posté le 05-10-2003 à 16:15:46    

Taz > Je vais utiliser la solution de SchnapsMann mais je garde ta solution sous la main. Je me laisse un peu de temps pour la mettre en place, si j'ai des soucis, je te demanderais :)
 
Merci encore !

Reply

Marsh Posté le 05-10-2003 à 16:17:20    

Taz a écrit :

ce n'est pas une solution de facilité


 
Toutes mes confuses, il faut que j'arrête d'écrire tout ce que je pense =)

Reply

Marsh Posté le 05-10-2003 à 16:20:11    

tant pis pour toi je t'aurais prévenu ... tu vas devoir te cogner toute la définition de la classe ...

Reply

Marsh Posté le 05-10-2003 à 16:21:51    

Question : la spécialisation de la classe toute entière m'oblige t'elle à réecrire toutes les fonctions membres du modèle ?

Reply

Marsh Posté le 05-10-2003 à 16:22:30    

Excellent, cross posting. Bon je laisse ma réponse pour la postérité.

Reply

Marsh Posté le 05-10-2003 à 17:31:18    

J'ai du mal :|
 
J'ai essayé de procéder de la sorte, ds ma class CMatrix, est-ce correct ?
 

Code :
  1. template<class T, unsigned short i_row, unsigned short i_column>
  2. class CMatrix {
  3. // ...
  4. template<unsigned short a, unsigned short b>
  5. static void computedet() ;
  6. // ...


 
Par exemple, je veux spécialiser cette fonction pour les matrices 2,2, comment dois m'y prendre ? :
 

Code :
  1. template<class T, unsigned short i_row, unsigned short i_column>
  2. template<>
  3. T CMatrix<T, i_row, i_column>::computedet<2,2>() {
  4. // ...
  5. }


 
 

seulement, défini une classe d'aide, avec une unique fonction membre static que tu spécialises autant que tu veux


 
Je ne vois pas comment faire :/ Comment produire une fonction générique, et des fonctions spécialisées en utilisant ce mécanisme ?
 
Désolé de pas comprendre au quart de tour, malgré la qualité de tes topics.


Message édité par Evadream -jbd- le 05-10-2003 à 17:34:20
Reply

Marsh Posté le 05-10-2003 à 18:02:35    

ça t'arrive de lire ?

Citation :

la spécialisation partielle de fonction n'est pas possible

[:quoted]

Reply

Marsh Posté le 05-10-2003 à 18:04:07    

car c'est une sorte de spécialisation. ça va pouvoir marcher, mais tu vas dupliquer trop de code.
donc fais une classe extérieure pour calculer les det
 

Reply

Marsh Posté le 05-10-2003 à 18:07:09    

Taz a écrit :

non, reste avec les templates. seulement, défni une classe d'aide, avec une unique fonction membre static que tu spécialises autant que tu veux


 
Je pensais que tu me proposais ici une solution pour pouvoir retrouver un mécanisme de spécialisation partiel pour des fonctions membres.
 
Lorsque j'ai utilisé la solution de SchnapsMann, tu as laissé entendre qu'il existait une meilleure solution  
 


tant pis pour toi je t'aurais prévenu ... tu vas devoir te cogner toute la définition de la classe ...

 
 
C'est cà que j'essaye en vain de réaliser, c'est tout :/
 

Reply

Marsh Posté le 05-10-2003 à 18:08:29    

Taz a écrit :


donc fais une classe extérieure pour calculer les det


 
Ok ! Merci !

Reply

Marsh Posté le 05-10-2003 à 18:09:56    

Evadream -jbd- a écrit :


 
Je pensais que tu me proposais ici une solution pour pouvoir retrouver un mécanisme de spécialisation partiel pour des fonctions membres.

c'est le cas. une classe avec une seule fonction statique entièrement dédiée au calcul d'une fonction. tu peux la spécialiser dans tous les sens, tu réécris tout le code à chaque fois, ce qui n'est pas plus volumineux qu'une hypotétique spécialisation partielle de fonctions

Reply

Marsh Posté le 05-10-2003 à 19:08:07    

/me n'avait remarqué que tu avais édité ton premier post pour y ajouter des exemples ! Merci !

Reply

Marsh Posté le 09-02-2004 à 20:20:49    

il est possible de spécialiser un destructeur virtuel ?
 
(je remonte un vieux topic, mais il me semble que ce soit la place de la question :p)
 
j'ai essayer de faire ca :
 

Code :
  1. template<typename T>
  2. class list
  3. {
  4.   // ...
  5.  
  6.   virtual ~list()
  7.   {
  8.   }
  9. };
  10. // spéclialisation pointeur
  11. template<typename T>
  12. virtual list<T*>::~list()
  13. {
  14. }


 
mais ca compile pas ...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 20:31:13    

BlackGoddess a écrit :

il est possible de spécialiser un destructeur virtuel ?
 
(je remonte un vieux topic, mais il me semble que ce soit la place de la question :p)
 
j'ai essayer de faire ca :
 

Code :
  1. template<typename T>
  2. class list
  3. {
  4.   // ...
  5.  
  6.   virtual ~list()
  7.   {
  8.   }
  9. };
  10. // spéclialisation pointeur
  11. template<typename T>
  12. virtual list<T*>::~list()
  13. {
  14. }


 
mais ca compile pas ...


 
Il me semble que tu ne peux pas spécialiser juste une fonction membre seule. Tu dois commencer par spécialiser la classe elle même et à l'interrieur la fonction membre.
 
 

Code :
  1. template<typename T>
  2. class list
  3. {
  4.   // ...
  5.  
  6.   virtual ~list()
  7.   {
  8.   }
  9. };
  10. // spéclialisation pointeur
  11. template<typename T>
  12. class list<T*>
  13. {
  14.   virtual list<T*>::~list()
  15.   {
  16.   }
  17. };


 
Edit : corrections pour que ça compile.


Message édité par Kristoph le 09-02-2004 à 20:33:57
Reply

Marsh Posté le 09-02-2004 à 21:06:10    

pourtant ceci compile :
(chez moi, je ne sais pas si c'est standard ...)
 

Code :
  1. template<bool bcrypt = false>
  2. class client_sock
  3. {
  4. void open()
  5. {
  6. }
  7. };
  8. template<>
  9. void client_sock<true>::open()
  10. {
  11. }


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 21:20:46    

ça l'est

Reply

Marsh Posté le 09-02-2004 à 21:24:19    

ca ne fonctionne pas pareil pour les destructeurs virtuels ?


Message édité par blackgoddess le 09-02-2004 à 21:24:32

---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 22:04:23    

apparement la spécialisation fonctionne (chez moi toujours) uniquement pour une spécialisation autre que les pointeurs...
est-ce un cas général ou est-ce mon compilo qui a du mal ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 22:32:22    

c'est quoi ton compilateur ?
les (destructeurs) virtuels ça n'existe pas

Reply

Marsh Posté le 09-02-2004 à 22:43:00    

vc++7
 
en fait
 
toujours avec  

Code :
  1. template<typename T>
  2.   class list
  3.   {
  4.       // ...  
  5.      
  6.       virtual ~list()
  7.       {
  8.       }
  9.   };


 

Code :
  1. template<>
  2. list<int>::~list()
  3. {
  4. }


 
fonctionne, mais pas
 

Code :
  1. template<typename T>
  2. list<T*>::~list()
  3. {
  4. }


 
 
j'ai fait un autre test :

Code :
  1. template<typename T>
  2. void t()
  3. {
  4. }
  5. template<typename T>
  6. void t<T*>()
  7. { // error C2768: 't<`template-parameter-257' *>' : explicit template arguments were not expected to be associated with this declaration
  8. }
  9. int main()
  10. {
  11.   t<void>();
  12.   t<void*>();
  13. }


 
la doc de l'erreur sur les msdn : http://msdn.microsoft.com/library/ [...] rC2768.asp
 
serait-ce un défaut du compilo pour cette spécialisation ?
 
(g bcp de mal a trouver de la doc sur la spécialisation pour pointeur sur le net ...)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 22:58:46    

pas de spécialization partielle de fonction template

Reply

Marsh Posté le 09-02-2004 à 23:01:43    

erf ca a deja été dit ...
 

Code :
  1. template<typename T>
  2. struct dtor
  3. {
  4. void del()
  5. {
  6. }
  7. };
  8. template<typename T>
  9. struct dtor<T*>
  10. {
  11. void del()
  12. {
  13. }
  14. };


 
compile pas non plus ...
 
j'ai lu que vc++7.1 devait supporter les spécialisations partielles de classes templates, je vais l'installer, on a changé recemment les licenses au taff ...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 23:04:31    

pourtant c'est parfaitement correct./
 
il donne quoi mon premier exemple (premier message) ?

Reply

Marsh Posté le 09-02-2004 à 23:07:30    

il fait les mêmes erreurs que mon précédent bout de code, une erreur de syntaxe sur le '>' de 'class Foo< T* >' suivie de quelques autres erreurs qui dérivent de celle la


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-02-2004 à 23:09:21    

ben tu vas ici http://forum.hardware.fr/hardwaref [...] -46017.htm
 
et tu leur dis que j'avais bien raison dans mon dernier message

Reply

Marsh Posté le 09-02-2004 à 23:11:12    

j'ai suivi le topic oui :p
 
ils parlaient de vc++7.1, v l'installer pour voir si ca résoud le pb.


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 10-02-2004 à 00:28:19    

taz a écrit :

ben tu vas ici http://forum.hardware.fr/hardwaref [...] -46017.htm
 
et tu leur dis que j'avais bien raison dans mon dernier message


 
tu t'en es pas remis hein ?
accroches toi, paske :
 

Code :
  1. template<typename T>
  2.   struct dtor
  3.   {
  4.      void del()
  5.      {
  6.      }
  7.   };
  8.  
  9.   template<typename T>
  10.   struct dtor<T*>
  11.   {
  12.      void del()
  13.      {
  14.      }
  15.   };


 
compile tres bien
 

Reply

Marsh Posté le 10-02-2004 à 00:30:21    

D'ailleurs tous tes exemples compilent...
 
Dis, fais pas d'actes desperés hein ? Tu sais, ainsi va le monde, tout change, tout evolue, les vérités deviennent inexactes et tout ca...

Reply

Marsh Posté le 10-02-2004 à 00:57:22    

fiou, install finie :)
 
la spécialisation partielle de fonction membres ne fonctionne toujours pas
 

Code :
  1. template<typename T>
  2. class list
  3. {
  4. void del_list()
  5. {
  6. }
  7. };
  8. template<typename T>
  9. void list<T*>::del_list() // erreur
  10. {
  11. }


 
par contre ce qu'a ecrit chrisbk compile en effet, je m'en suis donc tiré comme ca :
 

Code :
  1. template<typename T>
  2. class list
  3. {
  4. template<typename T>
  5. struct tdtor
  6. {
  7.  void del()
  8.  {
  9.   // ...
  10.  }
  11. };
  12. template<typename T>
  13. struct tdtor<T*>
  14. {
  15.  void del()
  16.  {
  17.   // ...
  18.  }
  19. };
  20. tdtor<T> dtor;
  21. public:
  22. virtual ~list()
  23. {
  24.  dtor.del();
  25. }
  26. };


Message édité par blackgoddess le 10-02-2004 à 00:59:43

---------------
-( BlackGoddess )-
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed