J'ai une grosse librairie avec beaucoup de classes <template> dépendantes
les unes des autres (www.cadoo.com si vous voulez avoir une petite idée...)
En VC6, je mettais toutes les implémentations des méthodes et fonctions
template dans le .h, avec des trucs du genre:
// fichier a.h
class B; // définie dans b.h
template <class T>
class A : public T
{
B b() const; // renvoie un objet de la classe b
};
template <class T> B A<t>::b() { ... } // implémentation de la méthode
// fichier b.h
class b {...}; // définie ici
et ça marchait parce que la méthode n'est instanciée que quand on s'en sert
(dans c.cpp)
Avec VC7 ça plante en compilant un autre fichier qui #include "a.h" sous
prétexte que b n'est pas défini...
et je ne peux pas ajouter un #include "b.h" avant car ça ferait des
références circulaires entre les #include.
J'ai essayé de mettre l'implémentation des templates dans des fichier .cpp,
tout compile ok, mais lorsque je linke ma belle librairie, le linker me dit
que toutes ces fonctions template ne sont pas définies...
En gros ma question c'est : où et comment instancier les templates pour que
ce soit pratique ?
Merci
--
Philippe Guglielmetti - www.dynabits.com
et ça marchait parce que la méthode n'est instanciée que quand on s'en sert (dans c.cpp)
Ca n'aurait pas dû.
Avec VC7 ça plante en compilant un autre fichier qui #include "a.h" sous prétexte que b n'est pas défini...
Et donc je commence à deviner pourquoi tout le monde dit que VC7 il est pas mal... (j'ai décroché au 5 ;)
Le problème dans ton code, est à la défition de A<T>::b(), qui retourne un B, et aura donc besoin du ctor de copie de B. Comme B n'est pas dépendant, il faut trouver ce constructeur (et donc la déf du type) avant la déf de A<T>::b().
Pour aller directement à la solution, je dirais que quelque chose comme ça pourrait convenir :
// fichier a.h class B; // définie dans b.h template <class T> class A : public T { B b() const; // renvoie un objet de la classe b };
// fichier a.cpp... certains préconiseront une autre extension // y a peut-être quelque chose de préconisé pour VC ? #include "a.h" #include "b.h" template <class T> B A<T>::b() const { ... } // implémentation de la méthode
// fichier b.h #include "a.h" // s'il y a dépendance circulaire class b {...}; // définie ici
// fichier c.cpp #include "a.cpp" A<machin> a; B b=a.b();
Je trouve ça un poil plus propre, parce qu'on peut inclure a.cpp sans avoir à penser à ramener autre chose. Un peu de self-containment, quoi.
J'ai vu le diagramme de classes sur cadoo, donc je n'essaierai pas a priori de remettre en cause l'interdépendance entre A et B (parce que pour justifier le problème, il faut quand même que la déf de B ait besoin de la déf de A<T>...).
J'ai essayé de mettre l'implémentation des templates dans des fichier .cpp, tout compile ok, mais lorsque je linke ma belle librairie, le linker me dit que toutes ces fonctions template ne sont pas définies...
Oui, parce que les fonctions templates (entre autres petites choses) ne peuvent être instanciées que si elles sont visibles dans l'unité de compilation (résultat du passage d'un fichier .cpp dans le préprocesseur, donc notamment après extension des include) qui les appelle.
On est censé pouvoir contourner cette «limitation» en rajoutant 'export' devant une déclaration de fonction template, mais «ça marche pas». Je dis ça, c'est pour ultra-simplifier ; les archives ont eu droit à l'explication plein de fois déjà. Et pour les gens qui sont pas d'accord, j'offre autant de ««««« et de »»»»» qu'il sera nécessaire ;)
Merci
Gourgouilloult du Clapotis HTH.. surtout que pour une fois, j'ai fait court ;)
Philippe Guglielmetti wrote:
// fichier a.h
class B; // définie dans b.h
template <class T>
class A : public T
{
B b() const; // renvoie un objet de la classe b
};
template <class T> B A<t>::b() { ... } // implémentation de la méthode
et ça marchait parce que la méthode n'est instanciée que quand on s'en sert
(dans c.cpp)
Ca n'aurait pas dû.
Avec VC7 ça plante en compilant un autre fichier qui #include "a.h" sous
prétexte que b n'est pas défini...
Et donc je commence à deviner pourquoi tout le monde dit que VC7 il est
pas mal... (j'ai décroché au 5 ;)
Le problème dans ton code, est à la défition de A<T>::b(), qui retourne
un B, et aura donc besoin du ctor de copie de B. Comme B n'est pas
dépendant, il faut trouver ce constructeur (et donc la déf du type)
avant la déf de A<T>::b().
Pour aller directement à la solution, je dirais que quelque chose comme
ça pourrait convenir :
// fichier a.h
class B; // définie dans b.h
template <class T>
class A : public T
{
B b() const; // renvoie un objet de la classe b
};
// fichier a.cpp... certains préconiseront une autre extension
// y a peut-être quelque chose de préconisé pour VC ?
#include "a.h"
#include "b.h"
template <class T> B A<T>::b() const { ... } // implémentation de la méthode
// fichier b.h
#include "a.h" // s'il y a dépendance circulaire
class b {...}; // définie ici
// fichier c.cpp
#include "a.cpp"
A<machin> a;
B b=a.b();
Je trouve ça un poil plus propre, parce qu'on peut inclure a.cpp sans
avoir à penser à ramener autre chose. Un peu de self-containment, quoi.
J'ai vu le diagramme de classes sur cadoo, donc je n'essaierai pas a
priori de remettre en cause l'interdépendance entre A et B (parce que
pour justifier le problème, il faut quand même que la déf de B ait
besoin de la déf de A<T>...).
J'ai essayé de mettre l'implémentation des templates dans des fichier .cpp,
tout compile ok, mais lorsque je linke ma belle librairie, le linker me dit
que toutes ces fonctions template ne sont pas définies...
Oui, parce que les fonctions templates (entre autres petites choses) ne
peuvent être instanciées que si elles sont visibles dans l'unité de
compilation (résultat du passage d'un fichier .cpp dans le
préprocesseur, donc notamment après extension des include) qui les appelle.
On est censé pouvoir contourner cette «limitation» en rajoutant 'export'
devant une déclaration de fonction template, mais «ça marche pas». Je
dis ça, c'est pour ultra-simplifier ; les archives ont eu droit à
l'explication plein de fois déjà. Et pour les gens qui sont pas
d'accord, j'offre autant de ««««« et de »»»»» qu'il sera nécessaire ;)
Merci
Gourgouilloult du Clapotis
HTH.. surtout que pour une fois, j'ai fait court ;)
et ça marchait parce que la méthode n'est instanciée que quand on s'en sert (dans c.cpp)
Ca n'aurait pas dû.
Avec VC7 ça plante en compilant un autre fichier qui #include "a.h" sous prétexte que b n'est pas défini...
Et donc je commence à deviner pourquoi tout le monde dit que VC7 il est pas mal... (j'ai décroché au 5 ;)
Le problème dans ton code, est à la défition de A<T>::b(), qui retourne un B, et aura donc besoin du ctor de copie de B. Comme B n'est pas dépendant, il faut trouver ce constructeur (et donc la déf du type) avant la déf de A<T>::b().
Pour aller directement à la solution, je dirais que quelque chose comme ça pourrait convenir :
// fichier a.h class B; // définie dans b.h template <class T> class A : public T { B b() const; // renvoie un objet de la classe b };
// fichier a.cpp... certains préconiseront une autre extension // y a peut-être quelque chose de préconisé pour VC ? #include "a.h" #include "b.h" template <class T> B A<T>::b() const { ... } // implémentation de la méthode
// fichier b.h #include "a.h" // s'il y a dépendance circulaire class b {...}; // définie ici
// fichier c.cpp #include "a.cpp" A<machin> a; B b=a.b();
Je trouve ça un poil plus propre, parce qu'on peut inclure a.cpp sans avoir à penser à ramener autre chose. Un peu de self-containment, quoi.
J'ai vu le diagramme de classes sur cadoo, donc je n'essaierai pas a priori de remettre en cause l'interdépendance entre A et B (parce que pour justifier le problème, il faut quand même que la déf de B ait besoin de la déf de A<T>...).
J'ai essayé de mettre l'implémentation des templates dans des fichier .cpp, tout compile ok, mais lorsque je linke ma belle librairie, le linker me dit que toutes ces fonctions template ne sont pas définies...
Oui, parce que les fonctions templates (entre autres petites choses) ne peuvent être instanciées que si elles sont visibles dans l'unité de compilation (résultat du passage d'un fichier .cpp dans le préprocesseur, donc notamment après extension des include) qui les appelle.
On est censé pouvoir contourner cette «limitation» en rajoutant 'export' devant une déclaration de fonction template, mais «ça marche pas». Je dis ça, c'est pour ultra-simplifier ; les archives ont eu droit à l'explication plein de fois déjà. Et pour les gens qui sont pas d'accord, j'offre autant de ««««« et de »»»»» qu'il sera nécessaire ;)
Merci
Gourgouilloult du Clapotis HTH.. surtout que pour une fois, j'ai fait court ;)
Loïc Joly
Gourgouilloult wrote:
Et donc je commence à deviner pourquoi tout le monde dit que VC7 il est pas mal... (j'ai décroché au 5 ;)
En fait, les gens disent généralement du bien de 7.1, et non de 7 qui n'est que 6++.
-- Loïc
Gourgouilloult wrote:
Et donc je commence à deviner pourquoi tout le monde dit que VC7 il est
pas mal... (j'ai décroché au 5 ;)
En fait, les gens disent généralement du bien de 7.1, et non de 7 qui
n'est que 6++.