Erreurs de linkages g++ incomprises

Erreurs de linkages g++ incomprises - C++ - Programmation

Marsh Posté le 07-08-2005 à 14:57:45    

Bonjour, à tous
J’ai des problèmes de linkage pour de nombreuses fonctions d’un projet que je compile avec g++.
J’ai trouvé une solution à une partie d’entre elles mais je ne comprend pas comment celle-ci peut résoudre mon problème et cela m’inquiète.
 
La situation est la suivante :
 
Par exemple, cette fonction(color.cpp) :  

Code :
  1. template <class CT>
  2. void Color<CT>::white(){
  3. if(empty()){
  4.  init(_RGB);
  5. }
  6. color[0]=maximum();
  7. color[1]=maximum();
  8. color[2]=maximum();
  9. }


pose cette erreur de linkage :

API/Component/classic.o(.text+0x48c):classic.cpp: undefined reference to `Color<float>::white()'


 
Solution, je met la fonction inline et sa definition dans color.h.
 
Je sais bien que si la fonction est inline elle n’est plus linké, je cherche à savoir comment ce peut il que les autres fonctions de cette même classe ne pose pas de problèmes, mais que cette fonction ci rende le linkage impossible?? La fonction maximum() est static et inline celà peut il être lié? (La fonction init() n'est n'y static ni inline et empty() est juste inline)
 
Je ne comprends pas ce que le [in-charge] nous apporte non plus ?
 
Si vous avez des suggestions de raisons possibles elle sont toujours les bien venues pour me donner des idées :)

Reply

Marsh Posté le 07-08-2005 à 14:57:45   

Reply

Marsh Posté le 07-08-2005 à 15:45:41    

mets tout ton code template dans le .h (ou alors plus la déclaration dans un .h, .h qui inclu un .tpp contenant les définition

Reply

Marsh Posté le 07-08-2005 à 15:53:51    

Mon "code template" c'est bien toute les fonctions membres d'une classe ayant un template?
 
Si c'est le cas comment ce fait-il que init() qui est membre de la même classe ne pose pas le même problème?  
 
Le problème qui me reste alors c'est que si je les mets dans un .h, je suis obligé de les inlinés sinon le linkage me fait des "refined ...." et je me disais que inliné certaine c'tai pas le top mais bon...si j'ai pas le choix ...

Reply

Marsh Posté le 07-08-2005 à 16:43:27    

non, les template ont une portée statique.

Reply

Marsh Posté le 07-08-2005 à 16:59:46    

Donc pour récapituler :

Classe avec un template -> Tout dans le .h


Toutes mes classes ont des templates et j'inlucdais tout avec des .hpp. Y'a quelques jours, j'ai eu la super mega bonne idée de me dire que ça devenait lourd de tout recompiler à chaque fois, alors j'ai fait un beau petit makefile et je me suis tout decoupé pour linké tout comme y faut ....... j'avais 5000erreurs de linkages là y m'en reste  1347 et si je comprend bien je suis bon pour tout me refaire dans l'autre sens...alors je prefère demander 2fois pour être sur...(non pas que je manque de confiance en Taz, malheureusement que trop du contraire)....Y'a pas un moyen pour linké des classes templates?

Reply

Marsh Posté le 07-08-2005 à 17:12:18    

Je viens de trouver ça sur le net mais je me demande ce que ça vaut :
 
Queue.h

Code :
  1. #ifndef QUEUE_H
  2. #define QUEUE_H
  3. #include <iostream>
  4. #include "QueueItem.h"
  5. using namespace std;
  6. template <class Type>
  7. class Queue ;
  8. template <class Type>
  9. ostream& operator<< (ostream&, Queue<Type>& );
  10. template <class Type>
  11. class Queue
  12. {
  13. public:
  14.     Queue() { front = back = NULL; }
  15.     ~Queue();
  16.     Type remove();
  17.     void add(const Type& );
  18.     bool is_empty();
  19.     friend ostream& operator<< <Type> (ostream&, Queue<Type>& );
  20. private:
  21.     QueueItem<Type> *front;
  22.     QueueItem<Type> *back;
  23. };
  24. #endif


 
Queue.c

Code :
  1. #include "Queue.h"
  2. template <class Type>
  3. void Queue<Type>::add(const Type &val)
  4. {
  5.     // allocate a new QueueItem object
  6.     QueueItem<Type> *pt = new QueueItem<Type>( val );
  7.     if (is_empty())
  8.         front = back = pt;
  9.     else
  10.     {
  11.         back->next = pt;
  12.         back = pt;
  13.     }
  14. }
  15. template <class Type>
  16. Type Queue<Type>::remove()
  17. {
  18.     Type retval;
  19.     if (is_empty() == true)
  20.     {
  21.         cerr << "remove() on empty queue\n";
  22.         exit(-1);
  23.     }
  24.     QueueItem<Type> *pt = front;
  25.     retval = pt->item;
  26.     front = front->next;
  27.     delete pt;
  28.     return retval;
  29. }
  30. template <class Type>
  31. bool Queue<Type>::is_empty() {
  32.    return (front == NULL);
  33. }
  34. template <class Type>
  35. Queue<Type>::~Queue() {
  36.    QueueItem<Type> *p = front;
  37.    while (p) {
  38.       QueueItem<Type> *q = p;
  39.       p = p->next;
  40.       delete q;
  41.    }
  42. }
  43. template <class Type>
  44. ostream& operator<< (ostream& out, Queue<Type>& q) {
  45.    for (QueueItem<Type> *p = q.front; p ; p = p->next)
  46.       out << p->item << endl;
  47.    return out;
  48. }
  49. //Aparement ceci arrangerait mon cas....
  50. template class Queue<int> ;
  51. template class Queue<double> ;
  52. template ostream& operator<< <int> (ostream& out, Queue<int>& q) ;
  53. template ostream& operator<< <double> (ostream& out, Queue<double>& q) ;


 
test.c

Code :
  1. #include <iostream>
  2. #include "Queue.h"
  3. int main () {
  4.    Queue<int> qi;
  5.    Queue<double> qd;
  6.    qi.add(7);
  7.    qi.add(10);
  8.    qi.add(15);
  9.    qd.add(10);
  10.    qd.add(15);
  11.    cout << "Removed <int> " << qi.remove() << endl;
  12.    cout << qi;
  13.    cout << "Removed <double>"  << qd.remove() << endl;
  14.    cout << qd;
  15.    return (0);
  16. }


 
 
Makefile :

CC = /usr/bin/g++
CFLAGS = -c
test: test.o Queue.o
 $(CC) -o test test.o Queue.o
test.o: test.c Queue.h QueueItem.h
 $(CC) $(CFLAGS) test.c
Queue.o: Queue.c Queue.h QueueItem.h
 $(CC) $(CFLAGS) Queue.c
clean:
 rm -f *.o test


 
Est ce une solution acceptable?
 
edit : parti tout seul..


Message édité par peak le 07-08-2005 à 17:14:13
Reply

Marsh Posté le 07-08-2005 à 17:14:37    

pas avec la majorité des compilateurs du marché, non. Note que mettre tout dans le .hpp ça ne veut pas dire inline : au final, il n'y a pas multiple définition, g++ les fusionne. Donc avoir séparé déclaration et définition comme tu l'as fait est positif : laisse dans le .hpp les versions inline (définis dans la déclaration de classe, ou marquées inline) et dans le .cpp (que tu devrais renommer en .tpp) tu conserves les définitions. Tu #include machin.tpp dans machin.hpp et ça va fonctionner très bien. C'est des fois un peu long à compiler, certes, mais ça fonctionne.
 
D'une manière générale, pour réduire ton temps de compilation, tu dois d'abord réduire les dépendances de compilation : ça passe d'abord par des .hpp les plus légers possibles qui n'incluent que le nécessaire (!= du nécessaire au .cpp correspondant !). Si tu le peux, utilise les forward déclaration dans tes .hpp. Même STL le prévoit ! Par exemple dans un .hpp, tu déclares une fonction utilisant un std::ostream& : pas la peine d'inclure tout le code <iostream>. <iosfwd> contient les forward déclarations qui suffisent. Et hop, tu évites à tous les .cpp incluant ton .hpp d'inclure <iostream> systématiquement.

Reply

Marsh Posté le 07-08-2005 à 17:20:36    

#ifndef QUEUE_H
 
pitié !
 
tu crois que y a combien de personne dans le monde qui ont utilisé le même schéma. Moi j'utilise des trucs comme H_BDEJEAN_QUEUE_1123427717 (nom, fichier, date).
 
putain, c'est quoi tous ces .c !
CC = /usr/bin/g++
CFLAGS = -c  
 
CXX, CXXFLAGS bordel !
 
 
ton # //Aparement ceci arrangerait mon cas.... c'est un modèle différent de celui de l'inclusion. Dans un .cpp séparé, tu définis tous les template que tu utilises : problème : c'est lourd et très difficile à maintenir, voir impossible humainement. Ça peut se justifier sur des cas très précis, mais ici, tu t'ennuies pour rien.
 
 
Sinon tes fonctions manquent de plein de const, is_empty() gagnerait à être inline. Seule une forward déclaration de QueueItem<Type> est nécessaire. Pas sa définition. Applique ce que je t'ai précédemment.

Reply

Marsh Posté le 07-08-2005 à 17:24:00    

Citation :

#ifndef QUEUE_H
 
pitié !

ouis, je sais bien c'était juste pour l'exemple  :ange:  
 
Je vais suivre tes conseils!
 
Puis c'est vrai que c'est pas plus mal de les avoir séparés, c'est un peu plus structuré aussi du point de vue des fichiers mais j'avais envie d'un beau petit make qui me le face étape par étape, tanpis  :( .
 
Merci !!!!
 :jap:  

Reply

Marsh Posté le 07-08-2005 à 18:25:27    

Taz a écrit :

pas la peine d'inclure tout le code <iostream>. <iosfwd> contient les forward déclarations qui suffisent.


En même temps <iosfwd>, c'est le seul que je connaisse ...
pour vector, string, etc, demerde toi :/


Message édité par ++fab le 07-08-2005 à 18:26:30
Reply

Sujets relatifs:

Leave a Replay

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