2009-05-23 14 views
10

J'ai lu à propos des typologies dans 'Modern C++ Design' et je l'ai compris comme une sorte d'union pour les types. En mettant différents types non liés dans une typelist, on peut l'utiliser pour représenter plus d'un type à la fois, sans héritage. J'ai testé typelist dans certaines fonctions simples avec des types primitifs, mais je ne pouvais pas obtenir l'un d'eux pour fonctionner.Comment utiliser les typelists

Est-ce que quelqu'un pourrait me dire si mon compte de typelists est juste et donner un exemple simple et concret comment employer des typelists dans le code moyen journalier? Merci d'avance. Au fait, j'utilise Windows et Visual Studio 2005 et son compilateur.

EDIT: mes exemples sont partis, j'utilise un projet sandbox en vs pour tester ces choses. Mais il était calme semblable au code dans le tutoriel Dobbs:

void SomeOperation(DocumentItem* p) 
{ 
    if (TextArea* pTextArea = dynamic_cast<TextArea*>(p)) 
    { 
     ... operate on a TextArea object ... 
    } 
    else if (VectorGraphics* pVectorGraphics = 
     dynamic_cast<VectorGraphics*>(p)) 
    { 
     ... operate on a VectorGraphics object ... 
    } 
    else if (Bitmap* pBitmap = dynamic_cast<Bitmap*>(p)) 
    { 
     ... operate on a Bitmap object ... 
    } 
    else 
    { 
     throw "Unknown type passed"; 
    } 
} 

Cela fonctionne, mais je ne vois pas l'avantage sur l'héritage qui est capable de faire la même chose. Et la distribution dynamique ne fonctionne pas sur les types primitifs. Est-il possible de l'utiliser comme une valeur de retour comme:

typedef Typelist<int, string> mylist 
mylist myfunction() { 
    if(foo == bar) 
     return 5; 

    return "five"; 
} 
+0

Ajoutez un exemple de code qui n'a pas fonctionné à votre question. –

Répondre

18

Les typelists sont des collections génériques de types à la compilation. Si vous utilisez dynamic_cast, il vous manque le point, car il ne devrait pas être nécessaire, car il s'agit d'un concept de compilation statique.

Cela fonctionne mais je ne vois pas l'avantage sur l'héritage qui est capable de faire la même chose.

Aucun type existant ne peut hériter de ce que vous voulez. Ce n'est simplement pas faisable, car ce type existant peut être un type intégré ou un type d'une bibliothèque. Pensez aux listes de types comme des extensions de listes de types (par exemple, dans std :: pair) pour un nombre raisonnable de types (au lieu de 2). Les typelists peuvent être utilisés pour créer une fonction permettant de passer un ensemble d'arguments à une fonction.Ceci est un morceau de code qui appelle des foncteurs généralisés de 5 paramètres (un autre concept de la conception C++ moderne) avec les arguments fournis dans un tupe (un autre) avec la typelist qui définit les types d'objets détenus dans le tuple:

//functor is just a holder of a pointer to method and a pointer to object to call this 
//method on; (in case you are unfamiliar with a concept) 
template<class R, class t0, class t1, class t2, class t3, class t4> 
R call(Loki::Functor<R,LOKI_TYPELIST_5(t0, t1, t2, t3, t4 
    )> func, 
    Loki::Tuple<LOKI_TYPELIST_5(t0, t1, t2, t3, t4)> tuple) 
{ 
    ///note how you access fields 
    return func(Loki::Field<0>(tuple), Loki::Field<1>(tuple), 
     Loki::Field<2>(tuple), Loki::Field<3>(tuple), 
     Loki::Field<4>(tuple)); 
} 

//this uses the example code 
#include<iostream> 
using namespace std; 

int foo(ostream* c,int h,float z, string s,int g) 
{ 
    (*c)<<h<<z<<s<<g<<endl; 
    return h+1 
} 

int main(int argc,char**argv) 
{ 
    Loki::Functor<int,LOKI_TYPELIST_5(ostream*, int, float, string, int)> f=foo; 
    //(...) 
    //pass functor f around 
    //(...) 
    //create a set of arguments 
    Loki::Tuple<LOKI_TYPELIST_5(ostream*, int, float, string, int)> tu; 
    Field<0>(tu)=&cout; 
    Field<1>(tu)=5; 
    Field<2>(tu)=0.9; 
    Field<3>(tu)=string("blahblah"); 
    Field<4>(tu)=77; 
    //(...) 
    //pass tuple tu around, possibly save it in a data structure or make many 
    //specialized copies of it, or just create a memento of a call, such that 
    //you can make "undo" in your application; note that without the typelist 
    //you would need to create a struct type to store any set of arguments; 
    //(...) 
    //call functor f with the tuple tu 
    call(f,tu); 
} 

Notez que seulement avec d'autres concepts comme les tuples ou les foncteurs, les typelists commencent à être utiles. En outre, j'ai connu Loki pendant environ 2 ans dans un projet et à cause du code du template (beaucoup), les tailles des exécutables dans les versions DEBUG tendent à être BIG (mon record était de 35 Mo). En outre, il y avait un peu de succès sur la vitesse de compilation. Rappelez-vous également que C++ 0x va probablement inclure un mécanisme équivalent. Conclusion: essayez de ne pas utiliser de typelists si vous n'avez pas à le faire.

+0

Merci beaucoup, vous avez éclairci certaines choses pour moi. Je pense que je devrais lire le chapitre à nouveau. – DaClown

5

Est-ce que this article du Journal du Dr Dobb l'aide tout?

4

Les typistes sont un moyen de transmettre des "listes de paramètres" à des méta-programmes modèles qui "s'exécutent" dans le cadre du processus de compilation. En tant que tels, ils peuvent être utilisés pour générer une sorte de type «union», mais ce n'est qu'une utilisation possible.

Pour un exemple «réel»: Nous avons utilisé des typologies pour générer automatiquement la méthode «QueryInterface» lors de l'implémentation d'objets COM dans la bibliothèque Comet.

Il vous a permis d'écrire du code comme ceci:

class Dog : public implement_qi<make_list<IAnimal, INoisy, IPersistStream> > 
{ 
    // The implement_qi template has provided 
    // an implementation of COM's QueryInterface method for us without 
    // having to write an ugly ATL "message map" or use any Macros. 
    ... 
} 

Dans cet exemple, « make_list » était un modèle utilisé pour générer une « liste de type » que le modèle implement_qi pourrait alors « énumérer sur » à generate the appropriate QueryInterface code.