Spécialisation template & Pétage de plomb

Spécialisation template & Pétage de plomb - C++ - Programmation

Marsh Posté le 04-07-2003 à 19:31:55    

Sous VC++ (.NET)
Quelqu'un peut m'expliquer pourquoi 1. marche et 2. me renvoie ma préférée LNK2005?? (les déf + déclarations dans un même fichier)
 
1. Sans LNK2005

Code :
  1. template< class T>
  2. class IndexFile : public FileManager {
  3. /* blahblah */
  4. private:
  5.     bool extractIndex(unsigned long indexToExtract) {
  6.          /* blahblah */
  7.     }
  8. };
  9. template<>
  10. bool IndexFile<char>::extractIndex(unsigned long indexToExtract) {
  11.     /* blahblah spécialisé pour les char*/
  12. }


 
2. Avec LNK2005

Code :
  1. template< class T>
  2. class IndexFile : public FileManager {
  3. /* blahblah */
  4. private:
  5.     bool extractIndex(unsigned long indexToExtract);
  6. };
  7. template<class T>
  8. bool IndexFile<T>::extractIndex(unsigned long indexToExtract) {
  9.     /* blahblah */
  10. }
  11. template<>
  12. bool IndexFile<char>::extractIndex(unsigned long indexToExtract) {
  13.     /* blahblah spécialisé pour les char*/
  14. }


 
Une idée?? Parce que ca commence a me prendre le choux!!


Message édité par Willyzekid le 04-07-2003 à 20:43:22

---------------
Horizon pas Net, reste à la buvette!!
Reply

Marsh Posté le 04-07-2003 à 19:31:55   

Reply

Marsh Posté le 05-07-2003 à 02:33:13    

tu veux la version longue ou courte?
 
version courte:
rajoute inline devant extractIndex
(par exemple)
 
LeGreg

Reply

Marsh Posté le 07-07-2003 à 23:52:08    

Ben avec la version longue ca serait pas mal non plus :D (je rentre tout juste de week-end)
 
Pourquoi je dois la faire inline cette fonction, ca m'echappe? (d'autant plus qu'elle est un peu longue!) Pourquoi diable quand on spécialise un template, la spécialisation doit-elle être inline?


---------------
Horizon pas Net, reste à la buvette!!
Reply

Marsh Posté le 08-07-2003 à 00:42:45    

Willyzekid a écrit :


Pourquoi je dois la faire inline cette fonction, ca m'echappe? (d'autant plus qu'elle est un peu longue!) Pourquoi diable quand on spécialise un template, la spécialisation doit-elle être inline?


 
Aucun compilateur c++ (enfin ceux que je connais, ie g++-3.2 et celui de visual .net) n'est capable de separer la declaration et la definition d'une classe en template.

Reply

Marsh Posté le 08-07-2003 à 01:43:46    

DJ_Mulder a écrit :


 
Aucun compilateur c++ (enfin ceux que je connais, ie g++-3.2 et celui de visual .net) n'est capable de separer la declaration et la definition d'une classe en template.
 


 
Merci, ca, j'avais remarqué... :)

Citation :

(les déf + déclarations dans un même fichier)


 
Cela dit, ca n'a pas grand chose a voir avec inline. C'est pas parce que c'est dans le même fichier (décla + def) que c'est nécessairement inline. C'est une condition nécessaire mais pas suffisante.


---------------
Horizon pas Net, reste à la buvette!!
Reply

Marsh Posté le 08-07-2003 à 07:41:37    

Le code template est réellement compilé lorsqu'une class template particulière est crée donc le compilo à besoin d'avoir acces à tous le code, il ne compilera pas le code qu'il ne voit pas, d'où l'erreur de link.
Si tu veux séparer la définition et la déclaration pour ton template tu dois inclure le deuxième fichier dans le premier.
 
montemplate.h:
template <class T> montemplate
{
};
 
#include "montemplate.cpp"

Reply

Marsh Posté le 08-07-2003 à 08:33:09    

gnoof a écrit :

Le code template est réellement compilé lorsqu'une class template particulière est crée donc le compilo à besoin d'avoir acces à tous le code, il ne compilera pas le code qu'il ne voit pas, d'où l'erreur de link.
Si tu veux séparer la définition et la déclaration pour ton template tu dois inclure le deuxième fichier dans le premier.
 
montemplate.h:
template <class T> montemplate
{
};
 
#include "montemplate.cpp"
 


 
A noter que tous les compilateurs n'ont pas ce type de problème, et que certains arrivent à compiler des templates défini en fichiers séparés.


---------------
brisez les rêves des gens, il en restera toujours quelque chose...  -- laissez moi troller sur discu !
Reply

Marsh Posté le 08-07-2003 à 09:47:37    

je croyais qu'aucun compilateur ne gérait le mot-clef export ?

Reply

Marsh Posté le 08-07-2003 à 10:36:14    

Citation :

Ben avec la version longue ca serait pas mal non plus


 
Cela vient de la maniere dont fonctionnent les compilateurs C.
 
Le C (et donc le C++) autorisent la programmation modulaire en fichiers .cpp séparés (qui constituent après le passage du préprocesseur, la translation unit). Ces fichiers séparés sont réunis à l'édition des liens.
Le probleme c'est que dans la définition du C initial, il ne peut y avoir deux fois le meme symbole défini dans plusieurs unités de traduction sinon il y a collision (LNK2005).
 
Comment faire donc? il faut que le corps de la fonction n'existe que dans un seul .cpp et soit occulté dans les autres. Les translation unit qui ont l'utilité de cette fonction se chargeront d'inclure le prototype de la fonction (comme une déclaration de fonction mais sans le corps), ou de s'appuyer sur le prototypage automatique (qui ne fonctionne qu'en C, a cause de la décoration des noms et la surcharge en C++).
 
Oui mais pour les fonctions inline ? Les fonctions inline sont un apport ultérieur du C++ qui a ensuite été intégré au C, et celles-ci requièrent que le corps de la fonction soit présent dans la translation unit courante pour que la fonction soit inlinable. Comme cela contredit la règle précédente, les fonctions inline sont donc la seule exception à la règle qui veut qu'il n'y ait qu'un seul corps de la fonction dans toutes les translation units. (je ne parle pas des templates qui n'existent vraiment qu'une fois instanciés).
 
Maintenant quid des classes ?
On peut avoir dans un fichier .h des définitions de classes et à l'intérieur de la définition, la définition complète de la méthode (body entre crochets).
Est-ce que cela ne contredit pas la règle ci dessus ?
Non, tout simplement parce que par défaut une méthode qui est entièrement défini dans le corps de la classe est inline par défaut (ce qui ne veut pas dire qu'elle soit inlinable et encore moins inlinée) mais ce qui veut dire que cela ne fera pas hurler l'éditeur de lien.
 
Par contre si tu ne fais que mettre le prototype de la méthode dans le corps de la classe et que tu mets le corps de la méthode en dehors des crochets de la classe sans préciser explicitement que le méthode est inline, alors la méthode n'est pas inline, et n'est donc pas soumise à l'exception des fonctions inlines.
 
Récapitulons:
 

Code :
  1. template<typename T> class toto {
  2.   void mafonction1() {}; // est inline
  3.   inline void mafonction2 (); // est inline
  4.   void mafonction3(); // n'est pas inline
  5. };
  6. template<typename T> void toto<T>::mafonction2()
  7. {
  8. }
  9. template<typename T> void toto<T>::mafonction3()
  10. {
  11. }


 
Et en l'absence du mot clé export, mafonction3() est impossible à mettre en oeuvre :/ .
 
Pour les compilateurs qui mettent en oeuvre export:
Comeau computing
(et oui c'est un peu tarabiscoté)
 
LeGreg

Reply

Marsh Posté le 08-07-2003 à 17:35:06    

Merci beaucoup LeGreg (!), gnoof et les autres, vos explications sont claires et limpides!
 
Cela dit, mon problème est trés spécifique. Les templates, je sais les définir que ce soit en fichié séparé ou non. Mon problème n'est pas là!
 
Mon problème porte sur la SPECIALISATION d'un template (c'est pourtant marqué dans le titre :)). Cette fois, puisqu'apparement j'étais pas clair, je vais donner beaucoup plus de détail.
 
1. Pour la clareté de la démonstration, tout les bouts de code suivant, même si, dans la réalité, ils sont éclatés en fichiers séparés ont été regroupé (et testé tel quel) dans un même fichier. Les mêmes erreurs sont produites.
 
2. Le cas classique. C'est le même que celui de mafonction3() de LeGreg à la différence qu'il compile parfaitement, sans erreur de compil. Et en fait, c'est là que je comprends plus LeGreg: son code compile parfaitement malgré ce qu'il montre avant.
 

Code :
  1. template< class T>
  2. class IndexFile : public FileManager {
  3. public:
  4.    bool extractIndex(const unsigned long indexToExtract);
  5. };
  6. template< class T>
  7. bool IndexFile <T>::extractIndex(const unsigned long indexToExtract) {
  8.    /* blahblah */
  9. }


 
3. Une première spécialisation d'une fonction d'une classe template. Toujours pas d'erreur au link ce qui parait normal avec l'explication de LeGreg (ma fonction étant inliné par défaut, donc pas de problème au link)...même si on est dans le cas d'une spécialisation de template (donc une seule fonction instanciée)
 

Code :
  1. template< class T>
  2. class IndexFile : public FileManager {
  3. public:
  4.    bool extractIndex(unsigned long indexToExtract) {
  5.         /* blahblah */
  6.    }
  7. };
  8. template<>
  9. bool IndexFile<char>::extractIndex(unsigned long indexToExtract) {
  10.    /* blahblah spécialisé pour les char*/
  11. }

 
 
4. Et enfin, vient l'erreur...que je comprends toujours pas. Ma spécialisation de template ne passe pas. Alors que logiquement à l'instanciation d'une classe IndexFile<char>, seule la fonction IndexFile<char>::extractIndex(...) est créé, l'autre devant être ignoré. Et inversement pour une classe IndexFile< N_IMPORTE_QUOI>

Code :
  1. template< class T>
  2. class IndexFile : public FileManager {
  3. /* blahblah */
  4. private:
  5.    bool extractIndex(unsigned long indexToExtract);
  6. };
  7. template<class T>
  8. bool IndexFile<T>::extractIndex(unsigned long indexToExtract) {
  9.    /* blahblah */
  10. }
  11. template<>
  12. bool IndexFile<char>::extractIndex(unsigned long indexToExtract) {
  13.    /* blahblah spécialisé pour les char*/
  14. }


 
Bref, je m'en suis sorti autrement (via héritage).


Message édité par Willyzekid le 08-07-2003 à 17:36:38

---------------
Horizon pas Net, reste à la buvette!!
Reply

Marsh Posté le 08-07-2003 à 17:35:06   

Reply

Marsh Posté le 08-07-2003 à 17:47:54    

Un autre exemple pour appuyer ma démo. Je suis allé cherché dans un cours en ligne (Cours C/C++, Christian Casteyde).
 
Bien sûr, ce code compile à merveille, c'est à se taper la tête contre les murs.
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. template <class T>
  4. class Item
  5. {
  6.    T item;
  7. public:
  8.    Item(T);
  9.    void set(T);
  10.    T get(void) const;
  11.    void print(void) const;
  12. };
  13. template <class T>
  14. Item<T>::Item(T i) // Constructeur
  15. {
  16.    item = i;
  17. }
  18. // Accesseurs :
  19. template <class T>
  20. void Item<T>::set(T i)
  21. {
  22.    item = i;
  23. }
  24. template <class T>
  25. T Item<T>::get(void) const
  26. {
  27.    return item;
  28. }
  29. // Fonction d?affichage générique :
  30. template <class T>
  31. void Item<T>::print(void) const
  32. {
  33.    cout << item << endl;
  34. }
  35. // Fonction d?affichage spécialisée explicitement pour le type int *
  36. // et la méthode print :
  37. template <>
  38. void Item<int *>::print(void) const
  39. {
  40.    cout << *item << endl;
  41. }


---------------
Horizon pas Net, reste à la buvette!!
Reply

Sujets relatifs:

Leave a Replay

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