template template parameters example

In this example you’ll learn how to use template template parameters.  We’ll use the template template parameter to specify the memory allocation policy of some imaginary ‘manager’ class that games often have.

We’ll pretend that we have some kind of texture manager that is responsible for the life of a texture class. We’ll be using a template parameter to specify which allocation policy the manager will
use.


// The only requirement for our memory allocation policy is to have a static 
// function that returns a pointer to the type we are creating. Each policy
// should have an identically named function. Here we are calling ours 
// 'construct'.
template <class t_constructed>
struct s_allocation_policy_operator_new
{
    // this "constructor" takes no parameters,
    // but we could also make versions that do...
    static t_constructed* construct()
    {
        return new t_constructed;
    }
}

// here is another allocation policy using malloc
template <class t_constructed>
struct s_allocation_policy_malloc
{
    static t_constructed* construct()
    {
        return (t_constructed*)malloc(sizeof(t_constructed));        
    }
}

// now for the fun part:
// here we are going to do a couple of interesting things, first note how we
// inherit our manager class from a template parameter. Interesting!
// This is how we can later specify which allocation policy to use.
template <template <class t_constructed> class t_allocation_policy>
class c_texture_manager : public t_allocation_policy
{
...

public:
    // here the c_texture isn't a template parameter because we are
    // pretending that our manager always manages c_texture objects.
    // but c_texture could easily be an abstract base class for all of
    // the various types of textures
    // you might think that t_constructed is meant to fill this role within
    // the definition of c_texture_manager, but actually t_constructed here isn't
    // a part of c_texture_manager's definition at all and could be omitted, but
    // it IS a parameter to t_allocation_policy.
    c_texture* create_texture();
}

...

// and here is the implementation of create_texture.
// you can see how c_texture fills in the template parameter t_constructed
// for t_creation_policy
template <template <class t_constructed> class t_creation_policy>
c_texture* c_texture_manager<t_creation_policy>::create_texture()
{
    // here we call the allocation policy's static construct function.
    return t_creation_policy<c_texture>::construct();
}

// finally, here's how the client code would look.
// this texture manager uses the new operator.
typedef c_texture_manager<s_allocation_policy_operator_new> t_texture_manager;

// or, we could specify a different allocation policy.
// this one would use malloc
typedef c_texture_manager<s_allocation_policy_malloc> t_texture_manager;

...

extern t_texture_manager g_texture_manager;

...

c_texture* new_texture= g_texture_manager.create_texture();

Perhaps when you start your game project you haven’t yet written your memory manager and you start off using a policy that allocates objects using the global new operator, with this pattern we can easily later switch out new and use a custom memory manager.

have fun!

Leave a Reply

Your email address will not be published.