Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use boost::mpl to compose policies?

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.

like image 724
ididak Avatar asked Nov 02 '08 09:11

ididak


2 Answers

Since no one answered the question satisfactorily, I spent sometime digging into the boost::mpl source. Man, it's not pretty with layers of macros and hundreds of lines of specialization classes. I now have more appreciation for the authors of the boost libraries to make meta programming easier and more portable for us. Hopefully C++0x will make library writers' life easier as well.

Anyway, the solution turns out to be simple and elegant.

First iter_fold is not what I want, as I couldn't figure out how to specify an iterator that can be deferenced to a null type. So I fiddled around with fold and find the following:

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

In order for this to work, I need to provide the Null type and a specialization for Cons:

struct Null { };

template<class PolicyT>
struct Cons<Null, PolicyT> {
  static void init() { PolicyT::init(); }
  static void cleanup() { PolicyT::cleanup(); }
};
like image 125
ididak Avatar answered Oct 16 '22 01:10

ididak


I think your problem is rather runtime invocation than metafunctions, because you want to call the init functions on the actual runtime objects.

You could try the runtime algorithms of mpl, like :

for_each<Policies>(InitPolicy());

with

struct InitPolicy() {
    template<class Policy>
    void operator() (Policy& p) { p.init_options(); }
};
like image 1
tabdamage Avatar answered Oct 16 '22 01:10

tabdamage