2008-11-02 12 views
6

he usado algo como lo siguiente para componer las políticas de mi solicitud:¿Cómo usar boost :: mpl para redactar políticas?

Las clases de política tener este aspecto:

struct Policy { 
    static void init(); 
    static void cleanup(); 
    //... 
}; 

template <class CarT, class CdrT> 
struct Cons { 
    static void init() { 
    CarT::init(); 
    CdrT::init(); 
    } 
    static void cleanup() { 
    CdrT::cleanup(); 
    CarT::cleanup(); 
    } 
    //... 
}; 

Para componer políticas:

typedef Cons<Policy1, Cons<Policy2, Cons<Policy3, Policy4> > > MyPolicy; 

Para utilizar MyPolicy:

init_with<MyPolicy>(...); 
//... 
cleanup_with<MyPolicy>(...); 

donde llamarían:

MyPolicy::init_options(); // calls Policy1 to 4's init in order 

y

MyPolicy::cleanup(); // calls Policy1 to 4's cleanup in reverse order 

Esencialmente, Contras construye una lista de tipos aquí. Es bastante sencillo. Sin embargo, la línea de contras typedef es un poco fea. Que va a ser ideal para tener combinador política que puede hacer esto:

typedef CombinePolicy<Policy1, Policy2, Policy3, Policy4> MyPolicy; 

Ya que podemos tener un número arbitrario de las políticas, la CombinePolicy necesitaría ayuda de la plantilla variadic en C++ 0x, que sólo está disponible de forma experimental en el corte compiladores de borde. Sin embargo, parece que la biblioteca boost: mpl resolvió/resolvió el problema utilizando un montón de trucos de preprocesamiento. Me supongo que podría utilizar algo como:

typedef mpl::list<Policy, Policy2, Policy3, Policy4> Policies; 

y luego llama:

init_with<Policies>(...); 

que luego utilizar:

typedef iter_fold<Policies, begin<Policies>::type, 
        some_magic_lambda_expression>::type MyPolicy; 

Obviamente, tengo un poco de problemas para encontrar la some_magic_lambda_expression aquí. Estoy seguro de que es bastante trivial para los expertos MPL aquí.

Gracias de antemano.

Respuesta

1

Creo que su problema es más bien la invocación de tiempo de ejecución que las metafunciones, porque desea llamar a las funciones init en los objetos de tiempo de ejecución reales.

Usted podría tratar de los algoritmos de tiempo de ejecución de MPL, como:

for_each<Policies>(InitPolicy()); 

con

struct InitPolicy() { 
    template<class Policy> 
    void operator() (Policy& p) { p.init_options(); } 
}; 
+0

Hay un pequeño error en tu ejemplo Esto podría hacer que funcione para el ejemplo. Puedo usar for_each para cada método. Pero lo que prefiero es tener una política combinada que se pueda transmitir, es decir, prefiero que la orden se aplique en tiempo de compilación en lugar de en tiempo de ejecución con for_each. – ididak

+0

Tal como lo veo, solo puede llamar metafunciones en tiempo de compilación, no veo forma de llamar a init_options() o cualquier otra función simple en tiempo de compilación. Entendí que desea aplicar automágicamente todas las Políticas en la lista de Políticas llamando a init_with en el tiempo de ejecución, que es lo que for_echo hace. aclare – tabdamage

+0

El objetivo es componer una clase de política en tiempo de compilación con la orden aplicada como en mi ejemplo original y los métodos realmente se invocan en tiempo de ejecución como MyCombinedPolicy :: init_options() etc. – ididak

1

Creo que estás buscando algo como:

typedef 
    iter_fold< 
    Policies, 
    begin<Policies>::type, 
    Cons<_1,_2> 
    >::type 
    MyType; 

También Puede que desee buscar en inherit_linearly<> si agrega un tipo de CRTP para invocar un Funciones de la base cableadas en tiempo de compilación.

+0

Esa fue mi conjetura original, pero no creo que esto sea correcto (no compilaría etc.) sin embargo. Además, no creo que inherit_linearly se ajuste al modelo aquí. Quiero hacer que la composición sea trivial y declarativa. Una secuencia de tipo sería la más fácil. – ididak

9

Dado que nadie respondió satisfactoriamente la pregunta, pasé algún tiempo investigando la fuente boost :: mpl. Hombre, no es bonito con capas de macros y cientos de líneas de clases de especialización.Ahora aprecio más a los autores de las bibliotecas de impulso para que la meta programación sea más fácil y portátil para nosotros. Es de esperar que C++ 0x también facilite la vida de los escritores de bibliotecas.

De todos modos, la solución resulta ser simple y elegante.

Primero iter_fold no es lo que quiero, ya que no pude encontrar la manera de especificar un iterador que se pueda referenciar a un tipo nulo. Así Jugueteé alrededor con doblez y encuentro lo siguiente:

typedef fold<Policies, Null, Cons<_1, _2> >::type MyPolicy; 

Para que esto funcione, debo proporcionar el tipo nulo y una especialización para Contras:

struct Null { }; 

template<class PolicyT> 
struct Cons<Null, PolicyT> { 
    static void init() { PolicyT::init(); } 
    static void cleanup() { PolicyT::cleanup(); } 
}; 
+0

elegante, estoy de acuerdo. se parece un poco a Alexandrescus type_list. En cierto nivel, la magia necesaria para hacer las cosas invisibles para los usuarios es bastante molesto ... – tabdamage

Cuestiones relacionadas