2009-05-23 10 views
10

He leído sobre listas de tipos en 'Modern C++ Design' y lo entendí como una especie de unión para tipos. Al poner tipos diferentes no relacionados en una lista de tipos, se puede usar para representar más de un tipo a la vez, sin herencia. Probé la lista de tipos en algunas funciones simples con tipos primitivos, pero no pude conseguir que ninguna de ellas funcionara.Cómo utilizar las listas de tipos

¿Alguien podría decirme si mi interpretación de las listas de tipos es correcta y dar un ejemplo simple del mundo real de cómo usar las listas de tipos en el código promedio diario? Gracias por adelantado.

Btw, estoy usando Windows y Visual Studio 2005 y su compilador.

EDITAR: mis ejemplos se han ido, uso un proyecto de recinto de seguridad en vs para probar esas cosas. Pero fue muy parecidos a codificar en Dobbs tutorial:

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"; 
    } 
} 

Esto funciona, pero no veo la ventaja sobre la herencia que es capaz de hacer lo mismo. Y el lanzamiento dinámico no funciona en los tipos primitivos. ¿Es posible utilizarlo como valor de retorno como:

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

    return "five"; 
} 
+0

Agregue un ejemplo del código que no funcionó a su pregunta. –

Respuesta

18

Las listas de tipos son colecciones genéricas de tipos de tiempo de compilación. Si usa dynamic_cast, le falta el punto, porque no debería ser necesario, porque es un concepto de tiempo de compilación estático.

Esto funciona pero no veo la ventaja sobre la herencia que es capaz de hacer lo mismo.

No puede hacer que ningún tipo hereda de lo que desee. Esto simplemente no es factible, porque este tipo existente puede ser un tipo incorporado o un tipo de una biblioteca. Piense en las listas de tipos como extensiones de listas de tipos (por ejemplo, en std :: pair) para cualquier cantidad razonable de tipos (en lugar de solo 2).

Las listas de tipos se pueden utilizar para crear una facilidad para pasar un conjunto de argumentos a una función.Esta es una pieza de código que llama functors generalizados de 5 parámetros (otro concepto del diseño Modern C++) con los argumentos suministrados en una tupla (otra más) con la lista de tipos que define los tipos de objetos contenidos en la tupla:

//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); 
} 

Tenga en cuenta que solo con otros conceptos como tuplas o funtores las listas de tipos comienzan a ser útiles. Además, he estado experimentando Loki durante aproximadamente 2 años en un proyecto y debido al código de la plantilla (una gran cantidad) los tamaños de los ejecutables en versiones DEBUG tienden a ser GRANDES (mi registro era de 35 MB o menos). También hubo un poco de golpe en la velocidad de compilación. También recuerde que C++ 0x probablemente incluirá algún mecanismo equivalente. Conclusión: trate de no utilizar listas de tipos si no es necesario.

+0

Muchas gracias, has aclarado algunas cosas para mí. Creo que debería leer el capítulo nuevamente. – DaClown

5

¿Tiene this artículo del Diario ayuda del Dr. Dobb alguna?

4

Las listas de tipos son una forma de pasar "listas de parámetros" a meta programas de plantillas que se "ejecutan" como parte del proceso de compilación.

Como tales, se pueden usar para generar algún tipo de tipo "unión", pero este es solo un uso posible.

Para un ejemplo del "mundo real": Usamos listas de tipos como una forma de generar automáticamente el método "QueryInterface" cuando implementamos objetos COM en la biblioteca Comet.

Permitió a escribir código como este:

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. 
    ... 
} 

En este ejemplo, "make_list" era una plantilla que se utiliza para generar una "lista de tipos", que la plantilla implement_qi podría entonces "enumerar más" a generate the appropriate QueryInterface code.

Cuestiones relacionadas