Specialisation partielle de fonction membre de classes templates...

Specialisation partielle de fonction membre de classes templates... - C++ - Programmation

Marsh Posté le 23-11-2005 à 01:13:17    

...C'est faisable ? Les choses n'ont pas évolué depuis le dernier sujet ?
 
ma reference
 

Code :
  1. #include <iostream>
  2. #include <string>
  3. using namespace std ;
  4. template <class T, int I>
  5. class test {
  6. public :
  7. void methode(T t) { cout << "generique " << t << " " << I << endl ; }
  8. // Plein d'autres méthodes
  9. } ; // class test
  10. /*
  11. provoque une erreur, mais c'est pourtant ce que je voudrais :  
  12. spécialiser le comportement d'une seule méthode...
  13. template <int I>
  14. void test<string,I>::methode(string t) { cout << "specifique string " << I << endl ; }
  15. */
  16. template <>
  17. void test<string,4>::methode(string t) { cout << "specifique string 4" << endl ; }
  18. int main(int argc, char* argv[])
  19. {
  20. test<long, 2>  tl2 ;
  21. test<string,3> ts3 ;
  22. test<string,4> ts4 ;
  23. tl2.methode(1234)         ;
  24. ts3.methode("blabla" )     ;
  25. ts4.methode("oui, lol" )   ;
  26. return 0 ;
  27. }


 
J'aurais aimé spécialiser le comportement d'une seule méthode de ma classe lorsqu'un seul des paramètres change. La spécialisation fonctionne bien quand je spécialise ma méthode complètement...
 
Pour l'instant j'ai fait le crados (j'ai sorti mon code spécialisé dans une fonction, et j'ai écrit autant de spécialisations complètes de ma méthode - 3 - que nécessaire), mais ca ne me plait pas.
 
 
 

Reply

Marsh Posté le 23-11-2005 à 01:13:17   

Reply

Marsh Posté le 24-11-2005 à 18:41:12    

Bide.

Reply

Marsh Posté le 24-11-2005 à 18:48:45    

bon anniversaire :hello:

Reply

Marsh Posté le 24-11-2005 à 19:32:44    

Ha oui, merci :D (3 ans déja...)
 
Et sinon, pour les templates  :whistle:

Reply

Marsh Posté le 24-11-2005 à 20:00:31    

comme tu as pu le remarquer, ce que tu veux faire n'est pas légal. Voici une modeste façon de contourner le problème, s'appuyant sur la résolution de surcharge.  
A la résolution de surcharge, une fonction non template est élue face à une fonction template uniquement s'il y a match exact. Les conversions implicites ne sont pas considérées. C'est pourquoi il faut fournir une surcharge char const*.
 

Code :
  1. #include <iostream>
  2. #include <string>
  3. #include <boost/type_traits/is_convertible.hpp>
  4. #include <boost/mpl/assert.hpp>
  5. template <class T, int I>
  6. class test
  7. {
  8. public:
  9.     template <class T2>
  10.     void methode( T2 const& t ) const
  11. {
  12.     BOOST_MPL_ASSERT(( boost::is_convertible<T,T2> ));
  13.     std::cout << "generique " << t << ' ' << I << '\n';
  14. }
  15.     void methode( std::string const& s ) const
  16. { do_it(); }
  17.     void methode( char const* s ) const
  18. { do_it(); }
  19. private:
  20.     void do_it() const
  21. { std::cout << "specifique string " << I << '\n'; }
  22. };
  23. int main()
  24. {
  25.     test<long,2>  tl2;
  26.     test<std::string,3> ts3;
  27.     test<std::string,4> ts4;
  28.    
  29.     tl2.methode(1234.9); // pas de warnings :/
  30.     tl2.methode<long>(1234.9); // pour avoir des warnings
  31.     ts3.methode("blabla" );
  32.     ts4.methode("oui, lol" );
  33. }

Reply

Marsh Posté le 24-11-2005 à 21:17:52    

edit (conneries supprimées) : Ha mais si, j'ai mal lu. Bon faudra vraiment que je réfléchisse à ton truc demain :D
 
Merci  :) !


Message édité par Mackila le 24-11-2005 à 21:20:08
Reply

Marsh Posté le 24-11-2005 à 23:23:13    

YES !
 
beaucoup plus simple en apparance. friend for ever :D
 
 

Code :
  1. #include <iostream>
  2. #include <string>
  3. template <class T, int I>
  4. class test
  5. {
  6. public:
  7.     friend void freef( T const& t )
  8. { std::cout << "generique " << t << ' ' << I << '\n'; }
  9.     friend void freef( std::string const& s )
  10. { std::cout << "specifique string " << I << '\n'; }
  11.     void methode( T const& t ) const
  12. { freef( t ); }
  13. };
  14. int main()
  15. {
  16.     test<long,2>  tl2;
  17.     test<std::string,3> ts3;
  18.     test<std::string,4> ts4;
  19.     tl2.methode( 1234 );
  20.     tl2.methode(1234.9);
  21.     ts3.methode("blabla" );
  22.     ts4.methode("oui, lol" );
  23.     freef( 5 ); // (*)
  24. }


 
(*) le minuscule (inexistant normalement) désagrément de cette technique est la pollution de la namespace scope par la fonction libre freef. Cepandant, avec un compilateur a la norme, cette ligne ne doit pas compiler. Si elle compile, c'est que le compilateur supporte encore l'extension "friend name injection" chère à Barton & Nackman. gcc < 4.1 la supporte par défaut, et une beta d'aout de gcc-4.1 que j'ai, continue de compiler ce code (?!).
 
edit : changement de l'ordre de declaration


Message édité par ++fab le 25-11-2005 à 08:12:47
Reply

Marsh Posté le 25-11-2005 à 00:38:21    

Heu j'ai pas tout suivi la  :??:  
 
Quelque chose me dit que je vais passer pas mal de temps à lire de gros pavés d'explication du bouzin, demain (enfin tout à l'heure).  :sweat:  
 
Ca me parait quand même vachement space comme truc, t'aurais pas deux trois explications sur le pourquoi et comment ca marche ? (il est minuit et demi, aussi, ca aide pas...)
 
edit : et passe pas sous VS7...

Message cité 2 fois
Message édité par Mackila le 25-11-2005 à 00:43:57
Reply

Marsh Posté le 25-11-2005 à 00:46:31    

Mackila a écrit :

Heu j'ai pas tout suivi la  :??:  
 
Quelque chose me dit que je vais passer pas mal de temps à lire de gros pavés d'explication du bouzin, demain (enfin tout à l'heure).  :sweat:


 
ne regarde que la deuxième solution, la première est vraiment mauvaise en fait.
 

Mackila a écrit :

Ca me parait quand même vachement space comme truc, t'aurais pas deux trois explications sur le pourquoi et comment ca marche ? (il est minuit et demi, aussi, ca aide pas...)


 
si, qu'est-ce que tu ne comprends pas ? ( en meme temps, c'est minuit et demi ...)

Reply

Marsh Posté le 25-11-2005 à 00:47:34    

Mackila a écrit :

edit : et passe pas sous VS7...


message d'erreur ?

Reply

Marsh Posté le 25-11-2005 à 00:47:34   

Reply

Marsh Posté le 25-11-2005 à 18:26:58    

Compilation...
testtemplate.cpp
d:\Documents\Mes projets\testtemplate\testtemplate\testtemplate.cpp(14) : error C2084: la fonction 'void test<T,I>::freef(const std::string & )' a déjà un corps
        with
        [
            T=long,
            I=2
        ]
        d:\Documents\Mes projets\testtemplate\testtemplate\testtemplate.cpp(16) : voir la définition précédente de 'freef'
        d:\Documents\Mes projets\testtemplate\testtemplate\testtemplate.cpp(24) : voir la référence à l'instanciation du modèle de classe 'test<T,I>' en cours de compilation
        with
        [
            T=std::string,
            I=3
        ]
d:\Documents\Mes projets\testtemplate\testtemplate\testtemplate.cpp(17) : fatal error C1903: impossible de récupérer à partir des erreurs précédentes ; arrêt de la compilation

Reply

Marsh Posté le 25-11-2005 à 18:45:58    

normal. Je me suis planté, la deuxième solution que j'ai proposée est complètement fausse, même si elle marche par chance chez moi (il faut dire que gcc ne m'a pas aidé d'un pouce). J'ai trouvé d'autres solutions ... J'espère que ce seront les bonnes :o
 
la première :  
 

Code :
  1. #include <iostream>
  2. #include <string>
  3. template <class T, int I>
  4. class test
  5. {
  6. public:
  7.     void methode( T const& t ) const
  8. { f( t ); }
  9. private:
  10.     template <class T2>
  11.     void f( T2 const& t ) const
  12. { std::cout << "generique " << t << ' ' << I << '\n'; }
  13.     void f( std::string const& s ) const
  14. { std::cout << "specifique string " << s << ' ' << I << '\n'; }
  15. };
  16. int main()
  17. {
  18.     test<long,2>  tl2;
  19.     test<std::string,3> ts3;
  20.     test<std::string,4> ts4;
  21.     tl2.methode( 1234 );
  22.     tl2.methode(123.9);
  23.     ts3.methode("blabla" );
  24.     ts4.methode("oui, lol" );
  25. }


 
la deuxième, plus compliqué, moins extensible, moins bonne tout court, mais intéressante (à partir d'un exemple à peine différent) :
 

Code :
  1. #include <iostream>
  2. #include <string>
  3. #include <boost/type_traits/is_same.hpp>
  4. namespace
  5. {
  6.     class Toto {};
  7. }
  8. template <class T1, class Bool>
  9. struct foo
  10. {
  11.     typedef Toto type;
  12. };
  13. template <class T1>
  14. struct foo<T1, boost::false_type>
  15. {
  16.     typedef T1 type;
  17. };
  18. template <class T1, class T2>
  19. struct ToFailOverload : foo<T1, typename boost::is_same<T1,T2>::type> {};
  20. template <class T1, class T2, class T3, int N>
  21. class Test2
  22. {
  23. private:
  24.     typedef double overloadType;
  25. public:
  26.     void methode( typename ToFailOverload<T2,overloadType>::type t2 ) const
  27. { std::cout << "generique " << t2 << ' ' << N << '\n'; }
  28.     void methode( overloadType s ) const
  29. { std::cout << "double " << s << ' ' << N << '\n'; }
  30. };
  31. int main()
  32. {
  33.     Test2<int,std::string ,std::string,4> test2;
  34.     test2.methode( "toto" );
  35.    
  36.     Test2<int,double,bool,4> test3;
  37.     test3.methode( 4.3 );
  38. }


 
avec peut etre un travail à faire pour épurer les cv-qualifiers, mais bon.


Message édité par ++fab le 25-11-2005 à 18:50:31
Reply

Marsh Posté le 25-11-2005 à 20:27:54    

La premiere me plait beaucoup plus (et en plus elle fonctionne :P).
J'adapterai ca sur mon code lundi (en rajoutant un bon pavé d'explications pour le gars qui repasserait éventuellement derrière, que les méthodes que je spécialise, c'est des opérateurs, ca a tendance à faire une syntaxe comme qui dirait un peu lourde :D )
 
Merci !  :jap:

Reply

Sujets relatifs:

Leave a Replay

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