I’ve been doing a lot of template-related stuff in C++ lately and thought it worth capturing some of it here, as I find myself reinventing the wheel every time I go through this process, which I’ve been doing since about 1995.
As with everything in C++ there are many ways of doing the same job, and depending on the specific job you are intending to do this may or may not be the useful to you. Under the peculiar constraints I’m working under these turn out the be the optimal way of doing things.
As well as the usual games with the curiously recurring template pattern (CRTP) the two things I’ve gotten the most mileage out of are double-dispatch and the use of statics in template methods to pass around a type-safe convenience pointer.
Double dispatch is a way of getting the appropriate template method called when you are passing a base type through the interface. Suppose I have a base class Foo with derived classes Bar and Baz, and that some other class Worker defines a template method that’s expected to take a derived type of Foo, but not Foo itself:
class Worker
{
...
template<typename TType>
void DoSomeWork(TType* pFooIsh);
...
};
In the case where we want to call DoSomeWork but we only have a pointer to the base class we would like the system to automatically infer the concrete type for us. This is done by double-dispatch, which can be implemented via a specialization of the DoSomeWork template method on the base type:
template<> void Worker::DoSomeWork<Foo>(Foo* pFoo) {pFoo->Forward(this);}
The Forward method of Foo is (typically pure) virtual, and re-implemented in Bar and Baz:
class Foo
{
public:
virtual void Forward(Worker* pWorker) = 0;
};
class Bar : public Foo
{
public:
// DoSomeWork now gets called with correct (derived) type
void Forward(Worker* pWorker) {pWorker->DoSomeWork(this);}
};
...and so on for Baz...
This ensures that DoSomeWork is instantiated for the appropriate sub-class even when all we have is a base class pointer.
The other trick I’ve used is a static in a template method to get type-safe access to a convenience pointer. The sub-system I’m working on is a controller for an existing class hierarchy, and I want to be able to pass around objects from that hierarchy in a type-safe but otherwise type-agnostic way. I don’t want to be down-casting all over the place just to get access to the concrete type, and I don’t want to template the entire framework on the type it happens to be controlling… there are enough subtle nuances of declaration order already without adding yet another type to the mix.
Creating a template method that contains a static of the appropriate type deals with this:
class Controller
{
public:
template<typename TControlled>
void Controlled(TControlled*& pControlled)
{
static TControlled* gpControlled = 0;
if (0 != pControlled)
{
gpControlled = pControlled;
}
else
{
pControlled = gpControlled;
}
}
...
};
The idiom is simple: pass in a non-null pointer to set the controlled object, pass in a null pointer to get it back.
The downside is that this is a static, so it’s shared by all instances of the class Controller, which unless Controlled happens to be a singleton is not what you want. This problem is easily worked around by replacing the Controlled pointer with a static map between this and the controlled object:
class Controller
{
public:
template<typename TControlled>
void Controlled(TControlled*& pControlled)
{
static std::map<Controller*, TControlled*> gmapControlled();
if (0 != pControlled)
{
gmapControlled[this] = pControlled;
}
else
{
pControlled = gmapControlled[this];
}
}
...
};
None of the code examples here have been compiled, so I’m sure they’re full of bugs, but hopefully the concepts are clear.