2008-11-02 11 views
6

Je l'ai utilisé quelque chose comme ce qui suit pour composer les politiques de mon application:Comment utiliser boost :: mpl pour composer des politiques?

Les classes politiques se présentent comme suit:

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

Pour composer les politiques:

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

Pour utiliser MaStratégie:

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

où ils appelleraient:

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

et

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

Essentiellement, Cons construit une liste de type ici. C'est plutôt simple. Cependant la ligne contre typedef est un peu moche. Ce sera idéal pour avoir combinateur de politique qui peut le faire:

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

Puisque nous pouvons avoir un nombre arbitraire de politiques, le CombinePolicy aurait besoin d'un soutien de modèle variadique en C++ 0x, qui est uniquement disponible expérimentalement en coupe compilateurs de bord. Cependant, il semble que boost: bibliothèque mpl résolu/travaillé autour du problème en utilisant un tas de tours de prétraitement. Je suppose que je pourrais utiliser quelque chose comme:

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

puis appelle:

init_with<Policies>(...); 

qui utiliserait alors:

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

De toute évidence, j'ai un peu de mal à déterminer some_magic_lambda_expression ici. Je suis sûr que c'est assez trivial pour les experts mpl ici.

Merci d'avance.

Répondre

1

Je pense que votre problème est plutôt l'appel d'exécution que les métafonctions, car vous voulez appeler les fonctions init sur les objets d'exécution réels.

Vous pouvez essayer les algorithmes d'exécution de mpl, comme:

for_each<Policies>(InitPolicy()); 

avec

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

Il y a un petit bug dans votre exemple. Cela pourrait faire travailler pour l'exemple. Je peux utiliser for_each pour chaque méthode. Mais ce que je préfère avoir une politique combinée qui peut être transmise, c'est-à-dire, je préfère que l'ordre soit appliqué au moment de la compilation plutôt qu'à l'exécution avec for_each. – ididak

+0

Comme je le vois, vous pouvez seulement appeler des métafonctions au moment de la compilation, je ne vois aucun moyen d'appeler init_options() ou toute autre fonction simple au moment de la compilation. J'ai compris que vous voulez appliquer automagiquement toutes les politiques de la liste des politiques en appelant init_with à l'exécution, ce que for_each fait. clarifier – tabdamage

+0

Le but est de composer une classe de politique au moment de la compilation avec l'ordre appliqué comme dans mon exemple original et les méthodes réellement sont invoquées à l'exécution comme MyCombinedPolicy :: init_options() etc – ididak

1

Je pense que vous cherchez quelque chose comme:

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

Vous aussi pourrait vouloir regarder dans inherit_linearly<> si vous buld-dans une sorte de CRTP pour invoquer un Les fonctions de base sont câblées au moment de la compilation.

+0

C'était ma supposition originale, mais je ne pense pas que ce soit correct (ne compilerait pas etc.) cependant. Aussi, je ne pense pas que inherit_linearly correspond au modèle ici. Je veux rendre la composition triviale et déclarative. Une séquence de type serait la plus facile. – ididak

9

Puisque personne n'a répondu à la question de manière satisfaisante, j'ai passé quelque temps à creuser dans la source boost :: mpl. Man, ce n'est pas joli avec des couches de macros et des centaines de lignes de classes de spécialisation.J'ai maintenant plus d'appréciation pour les auteurs des bibliothèques boost pour rendre la méta programmation plus facile et plus portable pour nous. Espérons que C++ 0x rendra la vie des rédacteurs de bibliothèque plus facile aussi.

De toute façon, la solution s'avère simple et élégante.

D'abord, iter_fold n'est pas ce que je veux, car je ne pouvais pas comprendre comment spécifier un itérateur qui peut être déféré à un type nul. Donc, je bidouillé autour avec pli et trouve les éléments suivants:

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

Pour que cela fonctionne, je dois fournir le type Null et une spécialisation pour Inconvénients:

struct Null { }; 

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

élégant, je suis d'accord. ressemble un peu à Alexandrescus type_list. À un certain niveau, la magie requise pour rendre les choses invisibles aux utilisateurs est assez dérangeante ... – tabdamage

Questions connexes