Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing partially specialized template as a template parameter

I have a class template, expecting some other template as a parameter:

template<
    class Key, 
    template <typename K,template <typename T> class Allocator> class Policy
>
class container {
     Policy<Key,Allocator>* _policy;
     //some code here
};

and usually i use it with the policy class like this:

template <class Key,template <typename T> class Allocator> class policy {
    //some code
};

but what if i have to pass additional template parameter to policy class? Something like:

template <time_t Age,class Key,template <typename T> class Allocator> class policy_3 {
    //some code
};

What can i do, to allow users of that class, pass the Age paratemeter without touching others? For example:

typedef container<key_type,policy_3<100500> > containerWithAge;
like image 546
akashihi Avatar asked Feb 24 '23 10:02

akashihi


1 Answers

You have two options: binding, and rebinding.

In binding, you adapt the ternary policy into a binary one, as expected by the template-template parameter Policy:

template <typename Key, template <typename T> class Allocator>
struct policy_3_100500 : ternary_policy<100500,Key,Allocator> {};

and use policy_3_100500 instead of policy_3<100500>.

To be closer to the syntax you're shooting for, you can use a nested class:

template <time_t Age>
struct policy_3 {
    template <typename Key, template <typename T> class Allocator>
    struct type : ternary_policy<Age,Key,Allocator> {};
};

and use policy_3<100500>::type instead of policy_3<100500>.

The only way to get exactly the syntax you want is to move the ::type into the class using the policy. That's the second option: rebinding (this is also used in std::allocator, btw). In this case, you pass the Policy as a normal template parameter, and assume a template metafunction, say bind, to exist:

template <time_t Age>
struct policy_3 {
    template <typename Key, template <typename T> class Allocator>
    struct bind : ternary_policy<Age,Key,Allocator> {};
};

While structually identical to the second option, the difference lies in who calls bind: In the first option (binding), it's the user of the policy class (by passing policy<100500>::type explicitly). Here, it's the class using the policy:

template <typename Key, typename Policy>
struct container {
    typename Policy::template bind<Key,std::allocator<Key>> * _policy;
    // ...
}:

As a general note, Policy classes are not usually passed as template-template arguments, but as normal template arguments (precisely because they may have a varying number of arguments themselves). The classes using the policy then assume a certain inner structure (typedefs, functions, meta functions, constants) to be present in the policy, of which bind is just an example.

like image 119
Marc Mutz - mmutz Avatar answered Apr 06 '23 01:04

Marc Mutz - mmutz