Ton compilo te dit que tu n'as pas le droit de répéter un argument par défaut, et il a raison (cf. n'importe quel bon bouquin de C++). Bilan, dans ton fichier src/TtsSimpleClientMrcp.cxx, change
int TtsSimpleClientMrcp::Speak2Wave(const char*, char*, TTSTextType =TT_Text)
en
int TtsSimpleClientMrcp::Speak2Wave(const char*, char*, TTSTextType)
Cherche l'endroit où se trouve le fichier libcvox.so. Le répertoire qui le contient doit se trouver dans les chemins de recherche des bibliothèques. Une fois que tu as trouvé ce chemin, rajoute le dans ton Makefile :
LDFLAGS=-L /mon/chemin/
Profites-en pour changer la ligne
CXX=G++-2
en
CXX=g++-2
ça t'évitera l'erreur de compilation que tu montres dans ton post précédent.
La variable LD_LIBRARY_PATH (et le fichier ld.so.conf, qui contient le même genre d'infos) n'intervient qu'à l'exécution, et pas à la compilation. C'est plutôt un problème au niveau des options -L ... (L majuscule) ou d'une variable LDFLAGS lors de l'utilisation d'un makefile.
C'est aussi pour cela que je veux qu'un entier soit implicitement converti vers un BigInt et pas l'inverse, autrement les résultats seront erronés.
Donc pas d'opérateur de conversion :-)
C'est que je voulais éviter. L'opérateur s'appuyant sur les constructeurs est déjà en place, mais l'utilisateur ne comprendra pas pourquoi dans un sens on peut directement comparer un BigInt à un entier, et pas dans l'autre ...
Dans ce cas, tu fait comme distait Pooly au début du thread (http://linuxfr.org/comments/506759.html#506759(...) ) et tu remplaces ta fonction membre pour l'opérateur < par une fonction non membre, qui est amie de la classe BigInt.
Pour ce faire, j'ai défini un constructeur de BigInt pour chaque type d'entier natif
Pourquoi pour chaque type ? Vu que les types entiers peuvent être promus entre eux, un constructeur prenant un int en paramètre suffit largement.
La classe est désormais pleinement fonctionnelle, sauf que j'ai besoin de pouvoir reconvertir l'objet en types natifs
Et si la valeur du BigInt est plus grande que celle du type natif que tu veux, il se passe quoi ?
Ce que je ferais, c'est de mettre des fonctions style GetLong, et un opérateur < pour comparer deux BigInt, la comparaison entier->BigInt étant gérée par le constructeur.
Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents.
En fait, après avoir pris connaissance de l'article de la FAQ Lite, T1 et T2 ne sont pas du même type au sens "C" du terme (en gros il ne font pas la même taille).
Mais d'un point de vue objet, si T2 hérite de T1, un truc du type top<T1> peut référencer top<T2> , puisque, apriori, tous les comportements de T2 sont compatible avec T1.
Dans ce cas, l'important n'est pas les comportments de T1 et de T2, mais ceux des templates associés top<T1> et top<T2>. On pourrait a priori penser que si T1 et T2 ont le même comportement, les templates auront fatalement le même. Ca marcherait bien si le C++ ne comportait pas de spécialisation des templates, qui te permet d'avoir des comportements différents, et donc des définitions différentes, pour certains paramètres du template. L'exemple classique est std::vector<bool> qui dans certaines implémentations de la SL n'est pas implémenté de la même façon que ses petits camarades std::vector<int> ou std::vector<char>.
L'exemple de code que tu donnes marche si la fonction fonc ne prend qu'un T est pas de vecteur de T. C'est le vecteur qui pose problème : un conteneur de T2* n'est pas un conteneur de T1*, et virer les pointeurs ne change pas le problème.
La solution qui me parait la plus simple est de ne pas construire des vecteurs de T2*, mais des vecteurs de T1*, et de vérifier dans topSpe::fonc que les T1* du vecteur pointent bien sur des vrais T2* (dynamic_cast est ton ami).
j'essaie de l'appeler avec un top ce qui ne devrait poser aucun problème puisque subTopParam hérite de topParam
Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents. C'est donc normal que ça plante. C'est un peu dans le même genre que l'exemple garage de voitures/garage de véhicules de la FAQ lite (http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-2(...) ).
À mon avis, la solution la plus propre et la plus simple est de faire de test une fonction template :
template<typename T>
void test (top<T> & t) {
cout << "test passé" << endl;
}
Et dans cette fonction de tester si le type T dérive bien de topParam. La bibliothèque boost fournit des classes de trait permettant de tester ce genre de choses (cf. boost::is_base_and_derived, http://www.boost.org/libs/type_traits/#relationships(...) ). Si tu ne veux/peux pas utiliser ce genre de choses, il faudra faire joujou avec static_cast, pour transformer un T* en topParam*, et voir si ça passe. Il te faudra ensuite gérer le cas où T ne dérive pas de topParam (lancer une exception, prévoir un comportement par défaut, ...).
Le problème vient du fait que tu mélanges du polymorphisme statique (résolu à la compilation, les templates) et du polymorphisme dynamique (résolu à l'exécution, l'héritage). As-tu vraiment besoin de faire ce genre de choses ?
Ce qu'on voit en général dans l'utilisation des templates (cf. la bibliothèque standard du C++, notamment les itérateurs et les algorithmes), c'est une doc genre "le paramètre Machin doit avoir telle propriété". Si l'utilisateur ne respecte pas les préconditions, tant pis, il n'avait qu'à lire la doc :-)
Dans ce cas, le main devrait afficher "coucou", mais ce n'est pas le cas car le linker considère que l'objet "unUniqueObjet" n'est pas utilisé par main, et il me le vire à l'edition des liens.
Si je comprends bien, tu veux utiliser unUniqueObjet dans ton main.
Ca me semble étrange que ce soit le linker qui râle : lors de la compilation de ton main, il n'y a aucune déclaration de unUniqueObject, et ça ne devrait donc pas compiler. Tout ce que tu utilises dans une unité de traduction (c.a.d ce que te donne le préprocesseur) doit y être déclaré.
Dans ton cas, il faut donc que tu déclares unUniqueObjet dans le fichier contenant la déclaration de tes classes de la bibliothèque.
P.S. avec du code qui compile réellement, ton exemple serait plus sympa à lire :-)
une classe IInterfaceS qui hérite de std::vector<IInterface*>
une classe NenfantS qui hérite de std::vector<Nenfant*>
C'est déconseillé d'hériter des conteneurs de la STL, surtout si tu utilises le polymorphisme et les fonctions dynamiques : les conteneurs n'ont pas de destructeur virtuel, donc si tu en hérites et que tu veux faire jouer le polymorphisme sur ces conteneurs, tu te retrouves avec une fuite de mémoire.
As-tu vraiment besoin de rajouter des fonctions à std::vector ?
En c++, si je ne me trompe pas, les seuls constructeurs implicites sont le contructeur par defaut et le constructeur par copie. Il ne sont ajoutés que si l'utilisateur ne défini pas lui même des contructeurs.
C'est presque ça : un constructeur par défaut est ajouté uniquement s'il n'y a aucun autre constructeur défini, que ce soit un constructeur de copie ou un autre constructeur. Pour le constructeur de copie, il est effectivement ajouté lorsque l'utilisateur n'en définit pas un lui même.
J'aurais plutôt tendance à déconseiller le bouquin de Delannoy : il utilise beaucoup de choses qui ne sont pas standard et certains chapitres sont très flous.
En bouquins français, je conseillerais "Programmation C++ par la pratique" (deuxième édition), de Oualline chez O'Reilly, et "L'essentiel du C++" de Lippman et Lajoie chez Vuibert. Le deuxième est vraiment très bien, mais coute vraiment très cher.
Vu que les constructeurs ne sont pas des fonctions membre (même s'ils en ont la syntaxe), ils ne sont pas hérités. Il va donc falloir les ré-implémenter explicitement.
Je n'ai rien vu dans la Boost qui permettrait de faire ça, mais je n'ai pas trop cherché.
Est-tu sur que tu as absolument besoin d'un héritage ?
Je commence à avoir pas mal de recul par rapport à ITK : l'utilisation du code existant est assez simple, après un temps d'adaptation aux techniques employées. Les exemples sont nombreux, le code est très bien documenté, beaucoup de techniques de traitement d'image sont déjà implémentées.
Par contre, rajouter un filtre est plus compliqué : il faut se faire la main sur des exemples simples pour comprendre le framework de la bibliothèque, et bien maitriser le C++.
Après avoir survolé CImg (la doc générée et le code), je suis un peu sceptique : un fichier de 6000 lignes, les algorithmes en fonction membres de la class CImg, ça me semble quelque chose de compliqué à maintenir et à étendre. Malgré ces reproches, CImg semble plus simple pour une première utilisation.
Pour reprendre les quatre points donnés par David en faveur de CImg (généricité, dépendances, multi-plateformes et taille du code généré), je donnerais un avantage à ITK pour la généricité, une égalité pour les dépendances et le multi-plateformes. Je ne comparerais pas la taille du code généré, le code d'ITK comprenant plus de 175000 lignes de code, et 44000 lignes d'exemples.
[^] # Re: bibliotheque manquante
Posté par Roulious . En réponse au message erreur de compil. Évalué à 1.
en
[^] # Re: bibliotheque manquante
Posté par Roulious . En réponse au message erreur de compil. Évalué à 1.
LDFLAGS=-L /mon/chemin/
Profites-en pour changer la ligne
CXX=G++-2
en
CXX=g++-2
ça t'évitera l'erreur de compilation que tu montres dans ton post précédent.
[^] # Re: bibliotheque manquante
Posté par Roulious . En réponse au message erreur de compil. Évalué à 1.
[^] # Re: Re : Ambigüités entre opérateurs
Posté par Roulious . En réponse au message Ambigüités entre opérateurs. Évalué à 2.
Donc pas d'opérateur de conversion :-)
Dans ce cas, tu fait comme distait Pooly au début du thread (http://linuxfr.org/comments/506759.html#506759(...) ) et tu remplaces ta fonction membre pour l'opérateur < par une fonction non membre, qui est amie de la classe BigInt.
# Re : Ambigüités entre opérateurs
Posté par Roulious . En réponse au message Ambigüités entre opérateurs. Évalué à 2.
Pourquoi pour chaque type ? Vu que les types entiers peuvent être promus entre eux, un constructeur prenant un int en paramètre suffit largement.
Et si la valeur du BigInt est plus grande que celle du type natif que tu veux, il se passe quoi ?
Ce que je ferais, c'est de mettre des fonctions style GetLong, et un opérateur < pour comparer deux BigInt, la comparaison entier->BigInt étant gérée par le constructeur.
[^] # Re: erratum
Posté par Roulious . En réponse au message templates et héritage.. Évalué à 1.
En fait, après avoir pris connaissance de l'article de la FAQ Lite, T1 et T2 ne sont pas du même type au sens "C" du terme (en gros il ne font pas la même taille).
Mais d'un point de vue objet, si T2 hérite de T1, un truc du type top<T1> peut référencer top<T2> , puisque, apriori, tous les comportements de T2 sont compatible avec T1.
Dans ce cas, l'important n'est pas les comportments de T1 et de T2, mais ceux des templates associés top<T1> et top<T2>. On pourrait a priori penser que si T1 et T2 ont le même comportement, les templates auront fatalement le même. Ca marcherait bien si le C++ ne comportait pas de spécialisation des templates, qui te permet d'avoir des comportements différents, et donc des définitions différentes, pour certains paramètres du template. L'exemple classique est std::vector<bool> qui dans certaines implémentations de la SL n'est pas implémenté de la même façon que ses petits camarades std::vector<int> ou std::vector<char>.
L'exemple de code que tu donnes marche si la fonction fonc ne prend qu'un T est pas de vecteur de T. C'est le vecteur qui pose problème : un conteneur de T2* n'est pas un conteneur de T1*, et virer les pointeurs ne change pas le problème.
La solution qui me parait la plus simple est de ne pas construire des vecteurs de T2*, mais des vecteurs de T1*, et de vérifier dans topSpe::fonc que les T1* du vecteur pointent bien sur des vrais T2* (dynamic_cast est ton ami).
[^] # Re: erratum
Posté par Roulious . En réponse au message templates et héritage.. Évalué à 3.
Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents. C'est donc normal que ça plante. C'est un peu dans le même genre que l'exemple garage de voitures/garage de véhicules de la FAQ lite (http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-2(...) ).
À mon avis, la solution la plus propre et la plus simple est de faire de test une fonction template :
template<typename T>
void test (top<T> & t) {
cout << "test passé" << endl;
}
Et dans cette fonction de tester si le type T dérive bien de topParam. La bibliothèque boost fournit des classes de trait permettant de tester ce genre de choses (cf. boost::is_base_and_derived, http://www.boost.org/libs/type_traits/#relationships(...) ). Si tu ne veux/peux pas utiliser ce genre de choses, il faudra faire joujou avec static_cast, pour transformer un T* en topParam*, et voir si ça passe. Il te faudra ensuite gérer le cas où T ne dérive pas de topParam (lancer une exception, prévoir un comportement par défaut, ...).
Le problème vient du fait que tu mélanges du polymorphisme statique (résolu à la compilation, les templates) et du polymorphisme dynamique (résolu à l'exécution, l'héritage). As-tu vraiment besoin de faire ce genre de choses ?
Ce qu'on voit en général dans l'utilisation des templates (cf. la bibliothèque standard du C++, notamment les itérateurs et les algorithmes), c'est une doc genre "le paramètre Machin doit avoir telle propriété". Si l'utilisateur ne respecte pas les préconditions, tant pis, il n'avait qu'à lire la doc :-)
[^] # Re: erratum
Posté par Roulious . En réponse au message templates et héritage.. Évalué à 2.
Je suppose que pour ton code, tu as quelque chose du genre :
Pourrais-tu poster un bout de code avec les templates ?
[^] # Re: Bonne question
Posté par Roulious . En réponse au message ld me détruit des symboles importants. Évalué à 1.
Si je comprends bien, tu veux utiliser unUniqueObjet dans ton main.
Ca me semble étrange que ce soit le linker qui râle : lors de la compilation de ton main, il n'y a aucune déclaration de unUniqueObject, et ça ne devrait donc pas compiler. Tout ce que tu utilises dans une unité de traduction (c.a.d ce que te donne le préprocesseur) doit y être déclaré.
Dans ton cas, il faut donc que tu déclares unUniqueObjet dans le fichier contenant la déclaration de tes classes de la bibliothèque.
P.S. avec du code qui compile réellement, ton exemple serait plus sympa à lire :-)
[^] # Re: Ça marche
Posté par Roulious . En réponse au message Déclencher et capturer une exception. Évalué à 1.
http://www.cplusplus.com/doc/tutorial/tut5-3.html(...)
# Re : Pour ma culture générale...
Posté par Roulious . En réponse au message Pour ma culture générale.... Évalué à 2.
Non, voir les points 21.2 et 21.3 de la FAQ Lite (http://www.parashift.com/c++-faq-lite/(...) pour les anglophones, http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index-fr.html(...) pour les autres)
Pour l'héritage :
C'est déconseillé d'hériter des conteneurs de la STL, surtout si tu utilises le polymorphisme et les fonctions dynamiques : les conteneurs n'ont pas de destructeur virtuel, donc si tu en hérites et que tu veux faire jouer le polymorphisme sur ces conteneurs, tu te retrouves avec une fuite de mémoire.
As-tu vraiment besoin de rajouter des fonctions à std::vector ?
[^] # Re: Ben oui, c'est le principe de la prog objet quand même ...
Posté par Roulious . En réponse au message Héritage et constructeurs. Évalué à 1.
C'est presque ça : un constructeur par défaut est ajouté uniquement s'il n'y a aucun autre constructeur défini, que ce soit un constructeur de copie ou un autre constructeur. Pour le constructeur de copie, il est effectivement ajouté lorsque l'utilisateur n'en définit pas un lui même.
[^] # Re: Delannoy
Posté par Roulious . En réponse au message Un livre pour apprendre le C++. Évalué à 1.
En bouquins français, je conseillerais "Programmation C++ par la pratique" (deuxième édition), de Oualline chez O'Reilly, et "L'essentiel du C++" de Lippman et Lajoie chez Vuibert. Le deuxième est vraiment très bien, mais coute vraiment très cher.
La FAQ Lite est très bien faite, voir http://www.parashift.com/c++-faq-lite/(...) pour la version anglaise et http://www.ensta.fr/~diam/c++/online/c++-faq-lite/(...) pour la VF (n'a pas l'air de répondre en ce moment).
# Les constructeurs ne sont pas des fonctions membre
Posté par Roulious . En réponse au message Héritage et constructeurs. Évalué à 1.
Je n'ai rien vu dans la Boost qui permettrait de faire ça, mais je n'ai pas trop cherché.
Est-tu sur que tu as absolument besoin d'un héritage ?
[^] # Re: bibliothèque de traitement d'images plus simple ?
Posté par Roulious . En réponse à la dépêche Quelques précisions sur la bibliothèque de traitement d'images 'INRIA'. Évalué à 4.
Par contre, rajouter un filtre est plus compliqué : il faut se faire la main sur des exemples simples pour comprendre le framework de la bibliothèque, et bien maitriser le C++.
Après avoir survolé CImg (la doc générée et le code), je suis un peu sceptique : un fichier de 6000 lignes, les algorithmes en fonction membres de la class CImg, ça me semble quelque chose de compliqué à maintenir et à étendre. Malgré ces reproches, CImg semble plus simple pour une première utilisation.
Pour reprendre les quatre points donnés par David en faveur de CImg (généricité, dépendances, multi-plateformes et taille du code généré), je donnerais un avantage à ITK pour la généricité, une égalité pour les dépendances et le multi-plateformes. Je ne comparerais pas la taille du code généré, le code d'ITK comprenant plus de 175000 lignes de code, et 44000 lignes d'exemples.