Как использовать boost :: mpl для составления политики? - PullRequest
6 голосов
/ 02 ноября 2008

Я использовал что-то вроде следующего для составления политик для моего приложения:

Классы политики выглядят так:

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

Для составления политики:

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

Чтобы использовать MyPolicy:

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

, куда они звонят:

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

и

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

По сути, Cons создает список типов здесь. Это довольно просто. Однако линия «typedef» довольно уродлива. Было бы идеально иметь объединитель политик, который может сделать это:

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

Поскольку у нас может быть произвольное количество политик, CombinePolicy потребуется поддержка шаблонов с переменным числом переменных в C ++ 0x, которая доступна только экспериментально в современных компиляторах. Однако, похоже, что библиотека boost: mpl решила / обошла проблему, используя кучу приемов предварительной обработки. Я думаю Я мог бы использовать что-то вроде:

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

, а затем звонит:

init_with<Policies>(...);

, который будет использовать:

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

Очевидно, у меня есть небольшая проблема с выяснением some_magic_lambda_expression здесь. Я уверен, что это довольно тривиально для экспертов mpl здесь.

Заранее спасибо.

Ответы [ 3 ]

9 голосов
/ 04 ноября 2008

Поскольку никто не ответил на вопрос удовлетворительно, я потратил некоторое время, копаясь в источнике boost :: mpl. Чувак, это не красиво со слоями макросов и сотнями строк классов специализации. Теперь я больше благодарен авторам библиотек надстроек за то, что они делают метапрограммирование более простым и портативным для нас. Надеюсь, C ++ 0x также облегчит жизнь авторам библиотек.

В любом случае, решение оказывается простым и элегантным.

Во-первых, iter_fold - это не то, что мне нужно, так как я не мог понять, как указать итератор, который можно отнести к нулевому типу. Поэтому я возился со сгибом и нашел следующее:

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

Для того, чтобы это работало, мне нужно предоставить тип Null и специализацию для Cons:

struct Null { };

template<class PolicyT>
struct Cons<Null, PolicyT> {
  static void init() { PolicyT::init(); }
  static void cleanup() { PolicyT::cleanup(); }
};
1 голос
/ 02 ноября 2008

Я думаю, вы ищете что-то вроде:

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

Вы также можете захотеть заглянуть в inherit_linearly <> , если вы вводите какой-то тип CRTP для вызова функций базы, встроенных во время компиляции.

1 голос
/ 02 ноября 2008

Я думаю, что ваша проблема скорее в вызове времени выполнения, чем в метафункциях, потому что вы хотите вызывать функции init для реальных объектов времени выполнения.

Вы можете попробовать алгоритмы выполнения mpl, как:

for_each<Policies>(InitPolicy());

с

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