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.
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(); }
};
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(); }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With