déclaration d'un template

déclaration d'un template - C++ - Programmation

Marsh Posté le 31-08-2003 à 01:19:22    

Bonjour,  
voilà, il y a une chose que je m'explique pas :
 
dans mon code, j'avais déclaré mon template comme suit :
 
un fichier tvalue.h:

Code :
  1. #ifndef tvalue_h
  2. #define tvalue_h
  3. template <class T>
  4. class TValue
  5. {
  6. T _val;
  7. public:
  8. TValue();
  9. TValue(T val);
  10. ~TValue();
  11. void set(T val);
  12. T get();
  13. };
  14. #endif


 
puis dans tvalue.cpp :

Code :
  1. #include "tvalue.h"
  2. template <class T>
  3. TValue<T>::TValue()
  4. {
  5. //
  6. }
  7. template <class T>
  8. TValue<T>::TValue(T val)
  9. {
  10. _val = val;
  11. }
  12. template <class T>
  13. TValue<T>::~TValue()
  14. {
  15. //
  16. }
  17. template <class T>
  18. void TValue<T>::set(T val)
  19. {
  20. _val = val;
  21. }
  22. template <class T>
  23. T TValue<T>::get()
  24. {
  25. return _val;
  26. }


 
puis autre part dans mon code :

Code :
  1. #include "tvalue.h"
  2. TValue<unsigned long> test;


 
la compilation ne marchait pas, au link j'avais des erreurs de symboles non résolus.
 
Alors que si je prends le contenu de tvalue.cpp et que je le mets dans tvalue.h, puis que je supprime tvalue.cpp du projet
comme cela :

Code :
  1. #ifndef tvalue_h
  2. #define tvalue_h
  3. template <class T>
  4. class TValue
  5. {
  6. T _val;
  7. public:
  8. TValue();
  9. TValue(T val);
  10. ~TValue();
  11. void set(T val);
  12. T get();
  13. };
  14. template <class T>
  15. TValue<T>::TValue()
  16. {
  17. //
  18. }
  19. template <class T>
  20. TValue<T>::TValue(T val)
  21. {
  22. _val = val;
  23. }
  24. template <class T>
  25. TValue<T>::~TValue()
  26. {
  27. //
  28. }
  29. template <class T>
  30. void TValue<T>::set(T val)
  31. {
  32. _val = val;
  33. }
  34. template <class T>
  35. T TValue<T>::get()
  36. {
  37. return _val;
  38. }
  39. #endif


 
puis autre part dans mon code :

Code :
  1. #include "tvalue.h"
  2. TValue<unsigned long> test;


cela fonctionne.
 
Pourquoi ?
 
(compilateur vc++7, mais je ne sais pas si ca a une incidence ou si c'est un standard)


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

Marsh Posté le 31-08-2003 à 01:19:22   

Reply

Marsh Posté le 31-08-2003 à 01:30:06    

faut tout mettre dans la meme unité de compilation

Reply

Marsh Posté le 31-08-2003 à 01:33:12    

ok, merci :)


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

Marsh Posté le 31-08-2003 à 01:34:18    

Ca ne fonctionne pas de déclarer les corps des templates dans un fichier d'implémentation à part. Les compilos c++ n'instancient un template en une classe qu'au moment ou l'instantiation se produit dans un source.
Comme à ce moment là seul le fichier d'include est disponible, si le corps des méthodes d'un classe template ou d'une fonction template n'étaient pas dans ce même fichier, ils ne sont pas instanciés. Donc il manque les symboles correspondants dans les fichiers objets, et ca ne link pas.
 

Reply

Marsh Posté le 31-08-2003 à 01:36:39    

ben c possible, soit avec un compilo qui gère le export, soit par instanciation explicite. tout ça est une longue histoire et toujours débattu

Reply

Marsh Posté le 31-08-2003 à 01:39:04    

Taz a écrit :

ben c possible, soit avec un compilo qui gère le export, soit par instanciation explicite. tout ça est une longue histoire et toujours débattu


 
Oui, ça fait des années que j'en entends parler, mais ça ne risque pas de rentrer tout de suite dans la norme.

Reply

Marsh Posté le 31-08-2003 à 01:40:08    

SchnapsMann a écrit :


 
Oui, ça fait des années que j'en entends parler, mais ça ne risque pas de rentrer tout de suite dans la norme.

sans doute pas pour les raisons que tu penses. c'est un tres long sujet, pour des bonnes infos sur les templates, y le bouquin de Jossutis

Reply

Marsh Posté le 31-08-2003 à 01:43:40    

Taz a écrit :

sans doute pas pour les raisons que tu penses. c'est un tres long sujet, pour des bonnes infos sur les templates, y le bouquin de Jossutis


 
le débat avait déjà lieu au début de mes études, et apparement la normalisation n'est pas encore pour tout de suite (bien que des protos fonctionnaient déjà bien il y a 10 ans).

Reply

Marsh Posté le 31-08-2003 à 01:46:10    

SchnapsMann a écrit :


 
le débat avait déjà lieu au début de mes études, et apparement la normalisation n'est pas encore pour tout de suite (bien que des protos fonctionnaient déjà bien il y a 10 ans).

la fonctionnalité existe bel est bien, le mot clef existe, mais ça ne passera pas dans la norme, pour une raison de cout, et par ce que le système d'export a aussi des problèmes

Reply

Marsh Posté le 02-09-2003 à 19:32:00    

Une solution est d'avoir 2 fichiers différents, comme pour toutes les autres classes, mais que le fichier tvalue.h fasse un #include du fichier tvalue.cpp.
 
Avantages : les lecteurs de ton programme (toi comris) ne seront pas déroutés, et le compilateur ne râlera pas.
 
Attention quand même si la classe template a des membres statiques et qu'elle est instanciée 2 fois dans ton programme avec les mêmes arguments mais dans 2 fichiers différents. Ca pourrait coincer à l'édition de liens ("duplicate definition" du membre statique). A vérifier.

Reply

Marsh Posté le 02-09-2003 à 19:32:00   

Reply

Marsh Posté le 03-09-2003 à 09:51:03    

merci pour toutes ces informations :)
 
un template c'est pas dans la norme ?!?


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

Marsh Posté le 03-09-2003 à 11:17:40    

BlackGoddess a écrit :

merci pour toutes ces informations :)
 
un template c'est pas dans la norme ?!?

ben si. mais le C++ (voir C++ D&E) est un langage très pragmatique et qui laisse le chanmp libre aux implémentations. donc pour les templates, on peut faire comme on veut: supporter le mot clef export, inclure le code dans chaque unité de compilation (tout dans un .h(pp) quoi) ou bien instancier manuellement ses templates.
 
la deuxième technique est la plus employée, la troisième est fastidieuse à la main (certains compilateurs fournissent des facilité, mais si tu change de compilo, boom, je n'est toujours pas trouver de soft permettant de faire (et en faire un n'est pas si simple que ça)) et le mot clef export, 1 seul compilateur au monde le supporte. en terme de comparaison, ça leur a pris autant de temps que réaliser un compilateur classic + bibliothèques STL ou d'implémenter un VM java, tout ça pour rajouter un simple mot (voir l'article "why we can't affort export" )

Reply

Marsh Posté le 03-09-2003 à 12:32:11    

Taz, je lis l'article, tu pourrais me dire ce que signifie :
ODR Checking
C++0x ?
 

Reply

Marsh Posté le 03-09-2003 à 12:37:30    

bon pour resumer ils ont travailler comme des oufs sur un mot cles a l'utilité douteuse :D

Reply

Marsh Posté le 03-09-2003 à 12:37:59    

One Definition Rule
C++0x, c'est le nom de la prochaine norme. ils ont espoire qu'elle sorte cette décénie, mais quand ....

Reply

Marsh Posté le 03-09-2003 à 12:40:25    

Taz a écrit :

One Definition Rule
C++0x, c'est le nom de la prochaine norme. ils ont espoire qu'elle sorte cette décénie, mais quand ....


 
(thks)

Reply

Marsh Posté le 03-09-2003 à 14:15:25    

Si j'me souviens bien en instanciant une (et une seule) specialisation d'un template y a moyen de l'exporter d'une DLL, avec le compilateur Intel (bon forcement c'est pas hyper pratique de pouvoir utiliser un template avec un seul argument). N'empeche export il a pas l'air terrible comme mot clé, j'préfèrerais un typeof, on verra au prochain standard.

Reply

Marsh Posté le 03-09-2003 à 14:32:39    

c'est quoi le rapport avec le DLL et ta remarque incompréhensible sur le compilo d'intel? on peut tout à fait séparer déclaration et implémentation, le tout c'est d'instancier à la main __toutes__ les utilisations templates, ce qui est fastidieux et parfois difficile, même avec un outil. mais ça fonctionne parfaitement.
 
export serait bien.
 
et ta remarque sur typeof, je la comprends pas non plus
 
 
par contre la prochaine norme amènera (peut être) le mot clef auto (ou je sais plus quoi), qui typera automatiquement une variable, qui permettra par exemple
 
auto v( fonction_qui_crache_du_template())
 
ou plus facilement
 
for(auto i(c.begin()); i!=c.end(); ++i)
 
tout ça à la phase de compilation bien sur, par simple déduction si j'ai bien compris

Reply

Marsh Posté le 03-09-2003 à 23:00:46    

autre question sur le même template
 
plutôt que de faire :
 
TValue<int> i;
i.set(3);
int j = i.get();
 
est-il possible de surcharger l'opérateur =, dans les 2 sens(pour get et pour set) ?
 
sinon, suis-je obligé de faire, dans la déclaration du template
~TValue() {} ou y a-t-il une autre solution plus directe pour montrer au compilo qu'il n'y a pas de code pour le destructeur ?


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

Marsh Posté le 03-09-2003 à 23:02:57    

l'opérateur = n'a qu'un sens
 
moi je te conseille:
de faire un  
constructeur(int i)
 
et  
 
operator int() const
 
 
 
après si ton destructeur ne fait rien, ne l'écris pas, el compilo le fera pour toi

Reply

Marsh Posté le 03-09-2003 à 23:14:33    

bin oui mais vu que ce sera pas forcement un int le <class T> je peux faire :
 

Code :
  1. template <class T>
  2. TValue<T>::TValue(T val)
  3. {
  4. _val = val;
  5. }


 
*part relire le cours*
 

Code :
  1. //copie
  2. template <class T>
  3. T &TValue<T>::operator=(const T &val)
  4. {
  5. _val = val;
  6. return *this;
  7. }
  8. T &TValue<T>::operator T()
  9. {
  10. return _val;
  11. }


 
le 3eme me parait bizarre ...
 
et apres donc si c'est exact je pourrais faire :
 
TValue<int> i(3);
TValue<int> j = i;
int k = i;
 
comment faire pour pouvoir faire
TValue<int> l;
l = 3;
?


Message édité par blackgoddess le 03-09-2003 à 23:15:08

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

Marsh Posté le 03-09-2003 à 23:18:47    

la déclaration du 3 n'est pas bonne, voir mon post précédent
 
 
 
x = 3; va fonctionner, la résolution donne en fait
 
x.operator=( Tvalue(3) )
 
tu peux effectivment ecrire un operateur = spécialiser, mais sauf cas spécial, ça n'as pas d'interet pour toi. donc fais plein de constructeur si tu veux, mais un seul operator=

Reply

Marsh Posté le 03-09-2003 à 23:35:03    

fo donc que j'écrive un cast pour chaque instanciation differente ?
 
par exemple  
 

Code :
  1. //copie  
  2. template <class T> 
  3. T &TValue<T>::operator int() const
  4. {
  5. return _val;
  6. }
  7. T &TValue<T>::operator long() const
  8. {
  9. return _val;
  10. }


 
pour pouvoir faire
TValue<int> t_i;
TValue<long> t_l;
 
int i = t_i;
long l = t_l;


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

Marsh Posté le 03-09-2003 à 23:37:38    

ben oui, mais t'as toujours faut dans le prototype
 
 
<rien< operator type() [const]

Reply

Marsh Posté le 03-09-2003 à 23:48:41    

ok, merci :)


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

Marsh Posté le 04-09-2003 à 08:35:06    

Taz a écrit :

c'est quoi le rapport avec le DLL et ta remarque incompréhensible sur le compilo d'intel? on peut tout à fait séparer déclaration et implémentation, le tout c'est d'instancier à la main __toutes__ les utilisations templates, ce qui est fastidieux et parfois difficile, même avec un outil. mais ça fonctionne parfaitement.
 
export serait bien.
 
et ta remarque sur typeof, je la comprends pas non plus
 
 
par contre la prochaine norme amènera (peut être) le mot clef auto (ou je sais plus quoi), qui typera automatiquement une variable, qui permettra par exemple
 
auto v( fonction_qui_crache_du_template())
 
ou plus facilement
 
for(auto i(c.begin()); i!=c.end(); ++i)
 
tout ça à la phase de compilation bien sur, par simple déduction si j'ai bien compris


 
T'sais t'es pas obligé de prendre tout le monde de haut..
La remarque sur la DLL c'est que meme en instanciant 36 versions d'un template (avec VC++) on peut pas les exporter d'une DLL, alors qu'avec le compilateur Intel on peut en exporter une...
Ma remarque sur typeof c'est qu'il y a des trucs bien plus utiles qui pourraient etre dans le standard au lieu de trucs comme export.
Et auto fonctionne effectivement comme ca, mais j'en ai pas l'utilite (alors que typeof oui).

Reply

Marsh Posté le 04-09-2003 à 08:43:46    

Taz a écrit :

__toutes__ les utilisations templates,
et ta remarque sur typeof, je la comprends pas non plus


 
il me semble __toutes__ explicite cela et ton histoire de DLL
 
et ta remarque sur typeof, si tu disais plutot ce que tu veux faire avec ? exemple ?

Reply

Marsh Posté le 04-09-2003 à 09:21:28    

Taz a écrit :


il me semble __toutes__ explicite cela et ton histoire de DLL
 
et ta remarque sur typeof, si tu disais plutot ce que tu veux faire avec ? exemple ?


 
1)
euh?
 
2)

Code :
  1. template <typename T> void machin( T beg, T end )
  2. {
  3.   typeof(*beg) temp;
  4.   for (; beg != end; ++beg)
  5.   {
  6.     temp = * beg;
  7.     /* ... */
  8.   }
  9. }


 
Edit: manquait le [/cpp]


Message édité par Ashe2 le 04-09-2003 à 09:22:21
Reply

Marsh Posté le 04-09-2003 à 09:34:31    

2) heink? je vois pas pourquoi y a besoin d'un nouveau mot-clef pour faire ça ?
 
j'ai retrouvé ça dans mon foutoir
 

Code :
  1. template <typename T>
  2. struct Swapper
  3. {
  4.   static void swap(T &a, T &b)
  5.   {
  6.     T tmp(a);
  7.     a = b;
  8.     b = tmp;
  9.   }
  10. };
  11. template <typename T>
  12. struct Swapper<T*>
  13. {
  14.   static void swap(T* a, T* b)
  15.   {
  16.     T tmp(*a);
  17.     *a = *b;
  18.     *b = tmp;
  19.   }
  20. };
  21. #include <iostream>
  22. int main()
  23. {
  24.   int i=1, j=2;
  25.   std::cout << i << ' ' << j << '\n';
  26.   Swapper<int>::swap(i, j);
  27.   std::cout << i << ' ' << j << '\n';
  28.   Swapper<int*>::swap(&i, &j);
  29.   std::cout << i << ' ' << j << '\n';
  30. }

Reply

Marsh Posté le 04-09-2003 à 09:38:58    

et j'ai toujours pas compris ton besoin de typeof. les templates et les pointeurs ça marche très bien ensemble, par spécialisation, ou tout simplement  
 

Code :
  1. template <typename T>
  2. void swap(T* a, T* b)
  3. {
  4.   T tmp(*a);
  5.   *a = *b;
  6.   *b = tmp;
  7. }


 
si tu travailles avec des paramètres templates qui sont des pointeurs, et bien utilise cette propriété. par ce que sinon, il suffit de se ramener avec un type qui possède son opérateur * et va chercher l'erreur ...


Message édité par Taz le 04-09-2003 à 09:44:00
Reply

Marsh Posté le 04-09-2003 à 12:17:13    

C'était plutot des iterateurs

Reply

Marsh Posté le 04-09-2003 à 12:24:48    

Ashe2 a écrit :

C'était plutot des iterateurs
 

et alors ?
 
la solution a tous tes problèmes
 

Code :
  1. #include <string>
  2. #include <iostream>
  3. template<typename InputIterator>
  4. inline typename InputIterator::value_type deference(InputIterator it)
  5. {
  6.   return *it;
  7. }
  8. template<typename T>
  9. inline T deference(T* ptr)
  10. {
  11.   return *ptr;
  12. }
  13. int main()
  14. {
  15.   std::string s("hello" );
  16.   std::cout << deference(s.begin()) << std::endl;
  17.   const char *cs("hello" );
  18.   std::cout << deference(cs) << std::endl;
  19. }

Reply

Marsh Posté le 04-09-2003 à 16:37:38    

J'crois pas qu'un pointeur possede un membre value_type, et c'est un parfait iterateur

Reply

Marsh Posté le 04-09-2003 à 16:41:14    

Ashe2 a écrit :

J'crois pas qu'un pointeur possede un membre value_type, et c'est un parfait iterateur

je crois pas que tu saches lire

Reply

Marsh Posté le 04-09-2003 à 17:36:56    

jcrois pas que je comprenne tout ca ...


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

Marsh Posté le 04-09-2003 à 17:40:29    

j'ai essayé de déchiffré la doc de la stl ou j'ai vu des iterateur, j'ai pas compris ... je verrais ca plus tard.
 
sinon juste une tite question pour etre sur
 
func(type &var) signifie, le & signifie qu'on passe un pointeur a la fonction, mais qu'on utilise directement la variable ?
 
par exemple
 
func(int &i) { i=3; }
 
int i;
func(&i);
 
est-ce exact ?


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

Marsh Posté le 04-09-2003 à 17:44:50    

Ne pas confondre pointeur et référence. Les pointeurs c'est toi qui les gère, les références c'est le compilo qui s'en occuppe.
 

Code :
  1. func(int &i) { i=3; }
  2. int i;
  3. func(i);

Reply

Marsh Posté le 04-09-2003 à 17:56:41    

donc  

Code :
  1. func(int &i) { i=3; } 
  2. int i; 
  3. func(i);


 
equivaut bien a :
 

Code :
  1. func(int *i) { *i=3; } 
  2. int i; 
  3. func(&i);


 
je repete p-e un peu mais je veux etre sur de bien avoir compris (vos réponses pour pas faire d'erreur)


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

Marsh Posté le 04-09-2003 à 18:05:14    

T'es pas obligé de passer par des fonctions :
 

Code :
  1. int a=1;
  2. int& ref=a;
  3. int b=1;
  4. int* pb = &b;

Reply

Marsh Posté le 04-09-2003 à 18:09:11    

ok, merci :)


---------------
-( 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