6

I have used something like the following to compose policies for my application:

The policy classes look like this:

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

To compose policies:

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

To use MyPolicy:

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

where they'd call:

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

and

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

Essentially, Cons constructs a type list here. It's pretty straight forward. However the typedef cons line is kinda ugly. It'll be ideal to have policy combiner that can do this:

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

Since we can have arbitrary number of policies, the CombinePolicy would need variadic template support in C++0x, which is only available experimentally in cutting edge compilers. However, it seems that boost:mpl library solved/worked around the problem by using a bunch preprocessing tricks. I guess I could use something like:

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

and then calls:

init_with<Policies>(...);

which would then use:

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

Obviously, I have a little trouble figuring out some_magic_lambda_expression here. I'm sure it's quite trivial for mpl experts here.

Thanks in advance.

4

3 回答 3

9

由于没有人满意地回答这个问题,我花了一些时间深入研究 boost::mpl 源代码。伙计,多层宏和数百行专业化类并不漂亮。我现在更加感谢 boost 库的作者,他们让元编程对我们来说更容易、更便携。希望 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(); }
};
于 2008-11-04T03:16:44.630 回答
1

我认为您的问题是运行时调用而不是元函数,因为您想在实际运行时对象上调用 init 函数。

您可以尝试 mpl 的运行时算法,例如:

for_each<Policies>(InitPolicy());

struct InitPolicy() {
    template<class Policy>
    void operator() (Policy& p) { p.init_options(); }
};
于 2008-11-02T12:40:55.320 回答
1

我认为您正在寻找类似的东西:

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

如果您内置某种 CRTP 以在编译时调用硬连线的基函数,您可能还想查看inherit_linearly<> 。

于 2008-11-02T19:51:59.163 回答