Hi everybody,
I am developing the design of an application and I thought I might apply some sort of the Visitor design pattern, but it turned out that it's not exactly what I am looking for. Maybe someone can point me to the variant I require in this case?
Much of my code has a template argument "ContainerType" like
template <class ContainerType>
class MyClass
{
public:
void doSomething(ContainerType& container) { ... }
};
There is a currently small but growing number of "Containers" that usually share many data fields.
template<class ContainedType>
struct ContainerBase
{
ContainedType data;
};
struct Container1: ContainerBase<A>, ContainerBase<B>
{};
struct Container2: ContainerBase<A>, ContainerBase<C>
{};
Container1 and Container2 are now used as template arguments for MyClass (and others), where A,B,C are some defined classes. (I have some method to do something like get<A>(container)
to access the contained data. This design provides compile-time safety that MyClass may be used with all container types that contain the required types.)
Now I would like to add the feature that "if the Container contains a certain type (e.g. A), then do something, otherwise do nothing".
This can be done with something that looks like the visitor (but note that no virtual methods are used). It even allows "if the Container contains A do this, if it contains D do something else, otherwise do nothing". This could be done with
template <class ContainerType>
class MyClass
{
public:
void doSomething(ContainerType& container)
{
container.accept(*this);
}
void visit(B& b){...}
void visit(D& d){...}
template<typename T>
void visit(T& t){}
};
struct Container1: ContainerBase<A>, ContainerBase<B>
{
template<class T>
void accept(T& t)
{
t.visit(ContainerBase<A>::data);
t.visit(ContainerBase<B>::data);
}
};
This is what I wanted, but I am looking for a better way to do it, because the implementation shown here requires implementing accept for every ContainerType. If someone derives from Container1
and ContainerBase<D>
but forgets to expand the accept methods, things will become bad. Even worse, I will require a const and non-const version of accept and some containers contain >5 types, so that won't look pretty either.
All container classes are build up by inheriting from ContainerBase<T>
multiple times, so I wondered if I could use this structure to implement the accept (and accept(..) const) in the ContainerBase class? I already looked at Lokis typelists but I don't know how to use them here. Do you have any idea?
Or is it possible to do this thing without the visitor-like structure?
Thanks a lot!
EDIT: I know I could go with RTTI but I'd like to avoid runtime checks and virtual methods if possible.