2008-11-02 14 views
6

użyłem czegoś takiego do komponowania polityk dla mojej aplikacji:Jak używać boost :: mpl do komponowania zasad?

Klasy polityki wyglądać następująco:

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

Aby skomponować polityk:

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

Aby korzystać MyPolicy:

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

gdzie mieliby zadzwonić:

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

i

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

Zasadniczo Wady konstruuje listę wpisz tutaj. To całkiem proste. Jednak linia przeciwna jest trochę brzydka. To będzie idealny mieć politykę sumator, który może to zrobić:

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

Ponieważ możemy mieć dowolną liczbę polityk, CombinePolicy musiałby o zmiennej liczbie argumentów pomocy szablonu w C++ 0x, który jest dostępny tylko eksperymentalnie cięcia kompilatory krawędzi. Wydaje się jednak, że boost: biblioteka mpl rozwiązała/rozwiązała problem za pomocą sztuczek preprocessingu grupowego. Chyba mogę używać coś takiego:

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

a następnie wywołuje:

init_with<Policies>(...); 

które następnie użyć:

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

Oczywiście, mam mały problem ze zorientowaniem się some_magic_lambda_expression tutaj. Jestem pewien, że dla ekspertów od mpl jest to dość trywialne.

Z góry dziękuję.

Odpowiedz

1

Myślę, że twój problem jest raczej wywołaniem czasu wykonywania niż metapunkcje, ponieważ chcesz wywoływać funkcje init na rzeczywistych obiektach środowiska wykonawczego.

można spróbować algorytmy wykonawcze MPL, jak:

for_each<Policies>(InitPolicy()); 

z

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

Jest trochę błędów w twój przykład. Może to zadziałać na przykład. Mogę użyć for_each dla każdej metody. Ale wolę mieć jedną wspólną politykę, którą można ominąć, tj. Wolę, aby kolejność była egzekwowana w czasie kompilacji, a nie w czasie wykonywania z for_each. – ididak

+0

Jak widzę, można wywoływać metafunkcje tylko podczas kompilacji, nie widzę możliwości wywołania init_options() lub innej prostej funkcji podczas kompilacji. Rozumiem, że chcesz automagicznie zastosować wszystkie zasady na liście zasad, wywołując init_with w czasie wykonywania, co robi for_each. proszę wyjaśnić – tabdamage

+0

Celem jest skomponowanie klasy polityki w czasie kompilacji z zamówieniem wymuszonym jak w moim oryginalnym przykładzie, a faktycznie metody są faktycznie wywoływane w czasie wykonywania, jak MyCombinedPolicy :: init_options() itp. – ididak

1

myślę szukasz czegoś podobnego:

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

też może zaglądać do inherit_linearly<>, jeśli wbudujesz coś w rodzaju CRTP, aby wywołać funkcje bazy są podłączone na stałe podczas kompilacji.

+0

To było moje oryginalne przypuszczenie, ale nie sądzę, że to jest poprawne (nie byłoby kompilacji itp.). Również nie sądzę, że dziedziczenie_linii pasuje do modelu tutaj. Chcę, aby kompozycja była banalna i deklaratywna. Typowa sekwencja byłaby najłatwiejsza. – ididak

9

Ponieważ nikt nie odpowiedział na pytanie w zadowalający sposób, spędziłem czas na wkopaniu się w źródło boost :: mpl. Człowieku, nie jest ładny z warstwami makr i setkami linii klas specjalizacyjnych.Teraz mam większe uznanie dla autorów bibliotek boost, aby uczynić programowanie meta łatwiejszym i bardziej przenośnym dla nas. Mam nadzieję, że C++ 0x również ułatwi pisarzom bibliotekę.

W każdym razie rozwiązanie okazuje się proste i eleganckie.

Pierwszy iter_fold nie jest tym, czego chcę, ponieważ nie mogłem wymyślić, jak określić iterator, który można odwołać do typu zerowego. Więc bawił się wokół z krotnie i znaleźć następujące:

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

Aby to działało, muszę dostarczyć Null rodzaj i specjalizacji dla Wady:

struct Null { }; 

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

elegancki, zgadzam się. wygląda trochę jak Alexandrecus type_list. Na pewnym poziomie magia wymagana do uczynienia rzeczy niewidocznymi dla użytkowników jest dość kłopotliwa ... – tabdamage

Powiązane problemy