2008-11-02 10 views
6

ich so etwas wie die folgenden Richtlinien für meine Anwendung zu komponieren verwendet haben:Wie boost :: mpl zum Verfassen von Richtlinien verwendet werden kann?

Die Policy-Klassen wie folgt aussehen:

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

Um MyPolicy zu verwenden:

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

Politik zu komponieren

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

wo würden sie anrufen:

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

und

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

wesentlichen Nachteile konstruiert eine Art Liste hier. Es ist ziemlich geradlinig. Die typedef con-Linie ist jedoch irgendwie hässlich. Es wird ideal seine Politik Kombinierer hat, kann dies tun:

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

Da wir beliebige Anzahl von Politik haben können, die CombinePolicy variadische Template-Unterstützung in C++ 0x brauchen würde, die experimentell nur verfügbar ist, beim Schneiden Edge-Compiler. Es scheint jedoch, dass boost: mpl library das Problem gelöst und bearbeitet hat, indem eine Reihe von Vorverarbeitungstricks verwendet wurde. Ich ich denke, so etwas wie verwenden:

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

und ruft dann:

init_with<Policies>(...); 

die dann verwenden würde:

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

Natürlich, ich habe ein wenig Mühe, herauszufinden, some_magic_lambda_expression hier. Ich bin mir sicher, dass es für MLP-Experten hier ziemlich trivial ist.

Vielen Dank im Voraus.

Antwort

1

Ich denke, Ihr Problem ist eher Laufzeitaufruf als Metafunktionen, weil Sie die Init-Funktionen auf die tatsächlichen Laufzeitobjekte aufrufen möchten.

Sie könnten die Laufzeit-Algorithmen von mpl versuchen, wie:

for_each<Policies>(InitPolicy()); 

mit

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

Es gibt einen kleinen Fehler in Ihr Beispiel. Dies könnte dazu führen, dass das Beispiel funktioniert. Ich kann for_each für jede Methode verwenden. Aber was ich bevorzuge, um eine kombinierte Politik zu haben, die herumgereicht werden kann, dh, bevorzuge ich die Reihenfolge, die zur Kompilierungszeit erzwungen wird, anstatt zur Laufzeit mit for_each. – ididak

+0

Wie ich es sehe, können Sie Metafunktionen nur zur Kompilierzeit aufrufen, ich sehe keine Möglichkeit, init_options() oder irgendeine andere einfache Funktion zur Kompilierzeit aufzurufen. Ich habe verstanden, dass Sie alle Richtlinien in der Richtlinienliste automatisch anwenden möchten, indem Sie init_with zur Laufzeit aufrufen, was for_each auch tut. Bitte klären Sie – tabdamage

+0

Das Ziel ist es, eine Policy-Klasse zur Kompilierzeit mit der Reihenfolge wie in meinem ursprünglichen Beispiel erzwungen und die tatsächlichen Methoden sind in der Tat zur Laufzeit wie MyCombinedPolicy :: init_options() etc. aufgerufen. – ididak

1

Ich glaube, Sie suchen so etwas wie:

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

Sie auch Vielleicht möchten Sie in inherit_linearly<> suchen, wenn Sie eine Art von CRTP buld-in eine a aufrufen Base-Funktionen sind zur Kompilierzeit fest verdrahtet.

+0

Das war meine ursprüngliche Vermutung, aber ich denke nicht, dass das korrekt ist (würde nicht kompilieren usw.). Ich denke auch nicht, dass inherit_linear dem Modell hier entspricht. Ich möchte die Komposition trivial und deklarativ machen. Eine Typenfolge wäre am einfachsten. – ididak

9

Da niemand die Frage zufriedenstellend beantwortete, habe ich mich irgendwann mit der boost :: mpl Quelle beschäftigt. Mann, es ist nicht schön mit Schichten von Makros und Hunderte von Linien von Spezialisierungsklassen.Ich habe jetzt mehr Wertschätzung für die Autoren der Boost-Bibliotheken, um die Metaprogrammierung für uns einfacher und tragbarer zu machen. Hoffentlich wird C++ 0x auch das Leben von Bibliotheksautoren erleichtern.

Wie auch immer, die Lösung erweist sich als einfach und elegant.

Zuerst Iter_fold ist nicht was ich will, da ich nicht herausfinden konnte, wie man einen Iterator spezifiziert, der zu einem Nulltyp referenziert werden kann. So fummelte ich um mit Falz und finden Sie die folgenden:

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

Damit dies funktioniert, muss ich die Null-Typ schaffen und eine Spezialisierung für Nachteile:

struct Null { }; 

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

elegant, ich stimme zu. sieht ein bisschen aus wie Alexandrescus type_list. Auf einer bestimmten Ebene ist die Magie, die benötigt wird, um die Dinge für die Benutzer unsichtbar zu machen, ziemlich lästig ... – tabdamage

Verwandte Themen