Design pattern “Container Visitor” without virtual methods?
我正在开发一个应用程序的设计,我想我可能会应用某种访问者设计模式,但结果发现这并不是我想要的。也许有人能给我指出这种情况下我需要的变体?
我的很多代码都有一个模板参数"containerType",比如
1 2 3 4 5 6 | template <class ContainerType> class MyClass { public: void doSomething(ContainerType& container) { ... } }; |
目前,共享许多数据字段的"容器"数量很少,但在不断增加。
1 2 3 4 5 6 7 8 9 10 | template<class ContainedType> struct ContainerBase { ContainedType data; }; struct Container1: ContainerBase<A>, ContainerBase {}; struct Container2: ContainerBase<A>, ContainerBase<C> {}; |
container1和container2现在用作myclass(和其他类)的模板参数,其中a、b、c是一些已定义的类。(我有一些方法可以做一些类似于
现在我想添加这样一个特性:"如果容器包含某种类型(例如A),那么就做点什么,否则什么也不做"。
这可以通过看起来像访问者的东西来实现(但请注意,没有使用虚拟方法)。它甚至允许"如果容器包含do-this,如果它包含d,则执行其他操作,否则不执行任何操作"。这可以用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 { template<class T> void accept(T& t) { t.visit(ContainerBase<A>::data); t.visit(ContainerBase::data); } }; |
这是我想要的,但我正在寻找一种更好的方法来实现它,因为这里显示的实现需要为每个containerType实现accept。如果有人从
所有容器类都是通过多次从
或者,在没有类似访客的结构的情况下,是否可以这样做?
谢谢!
编辑:我知道我可以使用rtti,但是如果可能的话,我想避免运行时检查和虚拟方法。
如果您可以更改容器类的定义方式,那么看起来使用boost.fusion很容易实现。
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <iostream> #include <boost/fusion/container/vector.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> struct A {}; struct B {}; struct C {}; namespace fusion = boost::fusion; struct Container1 : fusion::vector< A, B > {}; struct Container2 : fusion::vector< A, C > {}; struct doSomethingWithData { void operator()( B &b ) const { std::cout <<"do something with B" << std::endl; } void operator()( C &c ) const { std::cout <<"do something with C" << std::endl; } template < typename T > void operator()( T &t ) const { std::cout <<"Neither B nor C" << std::endl; } }; template < typename ContainerType > void doSomething( ContainerType &container ) { fusion::for_each( container, doSomethingWithData() ); } int main() { Container1 c1; doSomething( c1 ); std::cout <<"----------------------" << std::endl; Container2 c2; doSomething( c2 ); } |
可以使用boost::mpl定义包含类型的类型列表,如下所示:
1 | typedef boost::mpl::vector<A, B, C> ContainedTypes; |
使用boost::mpl::for_,您可以为每个包含的类型调用一个函数。
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template<class U> class Visitor { public: Visitor(MyClass<U>& item) : _item(item) {} template<class T> void operator() (T) { // Do what ever you want, this may be specialized as needed } private: MyClass<U>& item; } |
然后打电话
1 | boost::mpl::for_each<ContainedTypes> (Visitor(MyClass<ContainerType>& item)) |
这将为containedtypes中的每个类调用visitor的operator()。这种专门化方法的缺点是,对于T和U的组合,需要专门化operator()。
希望这有帮助,
马丁
在这种情况下,您需要的变体很可能是boost.variant:-)