views:

58

answers:

1

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) {}
};
+1  A: 

I had a similar problem, and did not find a desirable answer. From what I know, C++ doesn't have elegant support for variable amounts of template arguments, so you have to get around it by "wrapping" extra arguments in another class;

policy_base< twoArgs<part1, part2> >

You can pretty this up a little bit by putting making typedefs for twoArgs, but not by a lot in this basic case. (Remember, you can "do" templated typedefs by using member typedefs in templated classes.)

or by having many different declarations of the core template, with different args;

template< typename T1 > struct base {...}
template< typename T1, typename t2 > struct base {...}
//etc
Narfanator
Initially I don't like the multiple declarations idea since the purpose of this is to consolidate a lot of similar but slightly different objects to share code. With proper base classing though most of the copy/paste stuff could be pulled up; I'd have to pull more up than initially expected but... The twoArgs idea is also interesting and might be more so if named parameters were considered. Thanks. +1
Noah Roberts