我正在开发一个应用程序的设计,我想我可能会应用某种访问者设计模式,但事实证明这并不是我想要的。也许有人可以指出我在这种情况下需要的变体?
我的大部分代码都有一个模板参数“ContainerType”,例如
template <class ContainerType>
class MyClass
{
public:
void doSomething(ContainerType& container) { ... }
};
当前,通常共享许多数据字段的“容器”数量虽小但数量不断增加。
template<class ContainedType>
struct ContainerBase
{
ContainedType data;
};
struct Container1: ContainerBase<A>, ContainerBase<B>
{};
struct Container2: ContainerBase<A>, ContainerBase<C>
{};
Container1 和 Container2 现在用作 MyClass(和其他)的模板参数,其中 A、B、C 是一些已定义的类。(我有一些方法可以get<A>(container)
访问包含的数据。这种设计提供了编译时安全性,MyClass 可以与包含所需类型的所有容器类型一起使用。)
现在我想添加“如果容器包含某种类型(例如A),则执行某些操作,否则不执行任何操作”的功能。
这可以通过看起来像访问者的东西来完成(但请注意,没有使用虚拟方法)。它甚至允许“如果容器包含 A 执行此操作,如果它包含 D 执行其他操作,否则不执行任何操作”。这可以通过
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);
}
};
这是我想要的,但我正在寻找一种更好的方法来做到这一点,因为这里显示的实现需要为每个 ContainerType 实现接受。如果有人从accept方法派生但忘记扩展accept方法,事情就会变得糟糕Container1
。ContainerBase<D>
更糟糕的是,我需要一个 const 和 non-const 版本的 accept 并且一些容器包含 >5 种类型,所以看起来也不好看。
ContainerBase<T>
所有容器类都是通过多次继承构建的,所以我想知道是否可以使用这种结构来实现 ContainerBase 类中的接受(和接受(..)常量)?我已经看过 Lokis 类型列表,但我不知道如何在这里使用它们。你有什么主意吗?
或者是否有可能在没有访问者结构的情况下做这件事?
非常感谢!
编辑:我知道我可以使用 RTTI,但如果可能的话,我想避免运行时检查和虚拟方法。