Share via


fun with templates: part two - type factories

Scenario:

I have a template that takes a significant number of arguments, but in the most common use scenarios, there are some constraints that can be applied. I want to make it easier for clients to use the templates in the most common cases.

template <

typename command_base_t,

typename thread_policy_t,

typename completion_policy_t,

...

>

class CommandQueue

{

...

};

class ExecOnThreadPool;

class ExecSingleThreaded;

class SyncronousCompletion;

class AsyncCompletion;

Now, 99% of all of our usage is for either sync or async threadpool or single threaded command queues. I want to minimize the surface area used in common use cases to make it easier to modify the base template in the future.

Solution:

We can default the recusion policy, but that still requires the caller to be aware of all of the type names, order of parameters, etc. It also means that if we want to add some parameters later or tweak the class in some non-trivial way, we have to touch all of the client code. We can abstract a lot of this by creating templates that take just the thing that changes frequently, and abstracts away the actual template parameters.

template <typename command_base_t>

struct CommandQueueFactory

{

      typedef CommandQueue<

                  command_base_t,

                  ExecOnThreadPool,

                  SyncronousCompletion,

                  ...

            > SyncronousQueue;

      typedef CommandQueue<

                  command_base_t,

                  ExecOnThreadPool,

                  AsyncCompletion,

                  ...

            > AsyncronousQueue;

};

 

With this in place, most clients would use the template via the typedefs:

CommandQueueFactory<CommandBase>::SyncronousQueue myQueue;

CommandQueueFactory<CommandBase>::AsyncQueue myAsyncQueue;

Now most client code doesn't have a dependency on the specific policies or template parameter ordering of the original template class. When you need to go back and change the base template, you have far less code to touch to add a new parameter. Type factories are also useful in some scenarios involving template metaprogramming. Most notably, they can be used in typelists and traits classes to act as unspecifed template in metaprogramming constructs (I'll post more on this later).

[Special thanks to Tom M. for introducing me to this technique. As far as I can tell, he was the first to discover this trick.]