Policy based design and defaults.
- by Noah Roberts
Hard to come up with a good title for this question. What I really need is to be able to provide template parameters with different number of arguments in place of a single parameter. Doesn't make a lot of sense so I'll go over the reason:
template < typename T, template <typename,typename> class Policy = default_policy >
struct policy_based : Policy<T, policy_based<T,Policy> >
{
// inherits R Policy::fun(arg0, arg1, arg2,...,argn)
};
// normal use:
policy_base<type_a> instance;
// abnormal use:
template < typename PolicyBased > // No T since T is always the same when you use this
struct custom_policy {};
policy_base<type_b,custom_policy> instance;
The deal is that for many abnormal uses the Policy will be based on one single type T, and can't really be parameterized on T so it makes no sense to take T as a parameter. For other uses, including the default, a Policy can make sense with any T.
I have a couple ideas but none of them are really favorites. I thought that I had a better answer--using composition instead of policies--but then I realized I have this case where fun() actually needs extra information that the class itself won't have.
This is like the third time I've refactored this silly construct and I've got quite a few custom versions of it around that I'm trying to consolidate. I'd like to get something nailed down this time rather than just fish around and hope it works this time. So I'm just fishing for ideas right now hoping that someone has something I'll be so impressed by that I'll switch deities. Anyone have a good idea?
Edit: You might be asking yourself why I don't just retrieve T from the definition of policy based in the template for default_policy. The reason is that default_policy is actually specialized for some types T. Since asking the question I have come up with something that may be what I need, which will follow, but I could still use some other ideas.
template < typename T >
struct default_policy;
template < typename T, template < typename > class Policy = default_policy >
struct test : Policy<test<T,Policy>>
{};
template < typename T >
struct default_policy< test<T, default_policy> >
{
void f() {}
};
template < >
struct default_policy< test<int, default_policy> >
{
void f(int) {}
};
Edit:
Still messing with it. I wasn't too fond of the above since it makes default_policy permanently coupled with "test" and so couldn't be reused in some other method, such as with multiple templates as suggested below. It also doesn't scale at all and requires a list of parameters at least as long as "test" has. Tried a few different approaches that failed until I found another that seems to work so far:
template < typename T >
struct default_policy;
template < typename T, template < typename > class Policy = default_policy >
struct test : Policy<test<T,Policy>>
{};
template < typename PolicyBased >
struct fetch_t;
template < typename PolicyBased, typename T > struct default_policy_base;
template < typename PolicyBased >
struct default_policy : default_policy_base<PolicyBased, typename fetch_t<PolicyBased>::type> {};
template < typename T, template < typename > class Policy >
struct fetch_t< test<T,Policy> > { typedef T type; };
template < typename PolicyBased, typename T >
struct default_policy_base
{
void f() {}
};
template < typename PolicyBased >
struct default_policy_base<PolicyBased,int>
{
void f(int) {}
};