fra0 | Code :
- // THE QuiCK N' DIRTY TEMPLATE SURVIVAL KIT
- // oublies tout , le compilateur C++ moderne
- // il copie, il colle, il cherche, il remplace,ton code comme une dactylo déchainée
- // les templates ils te grondent si tu fais des bêtises
- // sinon ils font le travail de 50 ingénieurs allemands sous exta.
- // la définition canonique est assez simple
- template <class Noyau> struct Point
- {
- Noyau x,y,z;
- Point(Noyau _x=0,Noyau _y=0,Noyau _z=0):x(_x),y(_y),z(_z) {}
- };
- // l'instanciation aussi
- Point<double> origine;
- /* // qui remplace simplement "Noyau" par "double" et produit un imaginaire :
- struct __Point
- {
- double x,y,z;
- __Point(double _x=0,double _y=0,double _z=0):x(_x),y(_y),z(_z) {}
- };
-
- __Point origine; */
- // c'est déjà très pratique on peut écrire
- typedef Point<unsigned char> Couleur;
- const Couleur jaune(255,240,0);
- // après on peut très bien fournir des paramètres par défaut
- template <class Noyau=float> struct Point
- {
- Noyau x,y,z;
- Point(Noyau _x=0.0f,Noyau _y=0.0f,Noyau _z=0.0f):x(_x),y(_y),z(_z) {}
- };
- // qui permet des instanciations du genre
- Point<> bar;
- // les templates ne sont pas difficiles sur le nombre de paramètres et gèrent la précédence
- template <class Noyau=double,class Bool=bool,Bool checkBounds=true> struct Point
- {
- Noyau x,y,z;
- Point(Noyau _x=0.0f,Noyau _y=0.0f,Noyau _z=0.0f):x(_x),y(_y),z(_z)
- {
- if(checkBounds)
- {
- /* etc */
- }
- }
- };
- // les typedef prennent déjà une autre tournure...
- typedef Point<long double,bool,true> Point_Managed;
- typedef Point<float,size_t,false> Point_Savage;
- // ça reste un pré-processeur on peut très bien écrire
- template<int Major=0,int Minor=0,int Release=0,int Buid=-1> struct Version
- {
- void get(std::ostream&o)
- {
- o<<"v"<<Major<<'.'<<Minor<<'.'<<Release<<'.'<<Buid<<std::endl;
- }
- };
- static Version<0,2> version;
- // aucun stockage superflu, ça marche récursivement aussi
- Point<Point<int> > bar;
- /* // qui correspond à peu près à ça
- struct __Point
- {
- struct
- {
- int x,y,z;
- } __Point_;
-
- __Point_ x,y,z;
- };
-
- __Point bar;
- */
- // les appels suivants sont ok
- bar.x.y=0;
- bar.z=Point<int>(7,-1,-1);
- // en fait le compilateur ne vérifie le code que quand c'est nécessaire, on peut écrire directement
- template <class Objet,class Param> struct Executable
- {
- Objet o;
-
- // Executable(const Objet&_o):o(_o){}
-
- void operator()(const Param ¶m1=-1)
- {
- o.Go(param1);
- }
- };
-
- // sans rien connaitre de Objet ou de Param, cepedant seules les classes avec une méthode Go (et les bons paramètres) seront acceptées si ton code appelle l'opérateur () de Executable
-
- struct Foo
- {
- void Go(std::string name)
- {
- std::cout<<"Foo::"<<name<<" fait son truc"<<std::endl;
- }
- };
-
- class Bar
- {
- // du blabla
-
- public :
-
- // ...
-
- void Go(int id)
- {
- std::cout<<"un Bar fait le truc n°"<<id<<std::endl;
- }
- };
-
- // puis quelque part dans le code
-
- Executable<Foo,std::string> commande;
-
- // blablah
-
- commande("Hello" );
-
- // ou directement
-
- Executable<Bar,int>()(0x12345678);
- }
- // si les types sont connus à l'avance ça offre une alternative simple et efficace à l'héritage
- // où tout est mis à plat avant l'exécution... tu dois maintenant comprendre ça :
- template<int count> class unrolled_loop
- {
- public:
- unrolled_loop()
- {
- unrolled_loop<count-1>();
- std::cout <<"item #"<< count << std::endl;
- }
- };
- // ça prend tout son sens avec une spécialisation, la cerise sur le gâteau des templates :
- template <> class unrolled_loop<0>{};
- // ça arrête d'appeller récursivement le constructeur de unrolled_loop<count-1> pour le cas où count-1==0
- // à partir de la, il n'y a plus que les instructions std::cout <<"item #"... à ajouter au fichier objet/binaire.
- unrolled_loop<1024> scan_line; // 1024 tests & incréments économisés
- // yeah !!
|
Message édité par fra0 le 13-01-2006 à 06:44:29
|