Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1544 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  Erreurs de linkages g++ incomprises

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Erreurs de linkages g++ incomprises

n°1171697
peak
Posté le 07-08-2005 à 14:57:45  profilanswer
 

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 :)

mood
Publicité
Posté le 07-08-2005 à 14:57:45  profilanswer
 

n°1171715
Taz
bisounours-codeur
Posté le 07-08-2005 à 15:45:41  profilanswer
 

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

n°1171717
peak
Posté le 07-08-2005 à 15:53:51  profilanswer
 

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

n°1171748
Taz
bisounours-codeur
Posté le 07-08-2005 à 16:43:27  profilanswer
 

non, les template ont une portée statique.

n°1171757
peak
Posté le 07-08-2005 à 16:59:46  profilanswer
 

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?

n°1171759
peak
Posté le 07-08-2005 à 17:12:18  profilanswer
 

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
n°1171760
Taz
bisounours-codeur
Posté le 07-08-2005 à 17:14:37  profilanswer
 

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.

n°1171762
Taz
bisounours-codeur
Posté le 07-08-2005 à 17:20:36  profilanswer
 

#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.

n°1171763
peak
Posté le 07-08-2005 à 17:24:00  profilanswer
 

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:  

n°1171785
++fab
victime du syndrome IH
Posté le 07-08-2005 à 18:25:27  profilanswer
 

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

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  Erreurs de linkages g++ incomprises

 

Sujets relatifs
gerer les erreurs en HTMLProgramme en C avec erreurs
Quelques erreursErreurs sur mon site !!!
Script des erreurs dans le générateur d'évènementTerminer l'exécution d'une page au milieu / gestion d'erreurs
récupération des codes erreurs sur ftpCes foutus messages d'erreurs a la con
[RESOLU]Gestion des erreurs dans VBOn peut faire une boucle "anti-erreurs" en VB ?
Plus de sujets relatifs à : Erreurs de linkages g++ incomprises


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR