我对打字员很感兴趣。在这个URLhttp://drdobbs.com/184403813中,有一个很好的例子说明如何使用Typelist创建访问者模式。
关于这个例子,我有两个问题。我的两个问题在这个话题的结尾。
考虑下面的守则:
void SomeOperation(DocumentItem* p)
{
if (TextArea* pTextArea = dynamic_cast<TextArea*>(p))
{
... operate on a TextArea object ...
}
else if (VectorGraphics* pVectorGraphics =
dynamic_cast<VectorGraphics*>(p))
{
... operate on a VectorGraphics object ...
}
else if (Bitmap* pBitmap = dynamic_cast<Bitmap*>(p))
{
... operate on a Bitmap object ...
}
else
{
throw "Unknown type passed";
}
}根据Alexandrescu的说法,这一守则的不允许之处是:
除了非常丑陋之外,上面的代码还有一个概念性的问题,就是在编译时无法捕捉到“忘记处理这种类型”。
即将到来的打字员也是如此:
#include<iostream>
class null_typelist {};
template <class H, class T>
struct typelist
{
typedef H head;
typedef T tail;
};
template<class T1, class T2=null_typelist, class T3=null_typelist, class T4=null_typelist> struct cons;
template <class T1>
struct cons<T1, null_typelist, null_typelist,null_typelist>
{
typedef typelist<T1, null_typelist> type;
};
template <class T1, class T2>
struct cons<T1, T2, null_typelist, null_typelist>
{
typedef typelist<T1, typelist<T2,null_typelist> > type;
};
template <class T1, class T2, class T3>
struct cons<T1, T2, T3, null_typelist>
{
typedef typelist<T1, typelist<T2, typelist<T3,null_typelist> > > type;
};
template <class T1, class T2, class T3, class T4>
struct cons
{
typedef typelist<T1, typelist<T2, typelist<T3,typelist<T4, null_typelist> > > > type;
};
template <class tlist> class AdHocVisitor;
template <class H, class T>
class AdHocVisitor< typelist<H, T> > : public AdHocVisitor<T>
{
public:
virtual void Visit(H*) = 0;
template <class SomeClass>
void StartVisit(SomeClass* p)
{
if (H* pFound = dynamic_cast<H*>(p))
{
Visit(pFound);
}
else
{
AdHocVisitor<T>::StartVisit(p);
}
}
};
template <class H>
class AdHocVisitor< typelist<H, null_typelist> >
{
public:
virtual void Visit(H*) = 0;
template <class SomeClass>
void StartVisit(SomeClass* p)
{
if (H* pFound = dynamic_cast<H*>(p))
{
Visit(pFound);
}
else
{
throw "Unknown type passed";
}
}
};
struct DocElement{virtual ~DocElement(){};};
struct TextArea: DocElement{};
struct Bitmap: DocElement{};
struct VectorGraphics: DocElement{};
int main()
{
typedef cons<TextArea,Bitmap,VectorGraphics>::type MyHierarchy;
DocElement *p = new Bitmap;
struct ConcreteVisitor : AdHocVisitor<MyHierarchy>
{
void Visit(TextArea* p){std::cout << "I'm a textarea" << "\n";}
void Visit(VectorGraphics* p){std::cout << "I'm a VectorGraphics" << "\n";}
void Visit(Bitmap* p){std::cout << "I'm a Bitmap" << "\n";}
};
ConcreteVisitor visitor;
visitor.StartVisit(p);
delete p;
std::cin.get();
}1-我们还有dynamic_cast和一个虚拟函数。所以我看不出介绍打字员有什么好处?
在这篇文章的结尾,Alexandrescu给出了一些改进代码的建议,但是我看不出如何实现这些代码,有人能帮我吗?
谢谢
发布于 2011-04-07 09:42:11
如果您有50种DocElement类型呢?对于第一个示例,您需要50个if语句,而对于第二个示例,只需要有一个包含50个元素的打字员。
您还可以考虑添加另一个DocElement时会发生什么。在第一个例子中,您需要去更改if-else语句。使用类型列表,您可以将新类型添加到类型列表的末尾。
类型列表代码看起来可能有很多开销,但是您只编写一次,然后只使用它,而不是添加ifs或case和代码(随着时间的推移会变得相当大),您只需将类型添加到类型列表中即可。从维护的角度来看,类型列表代码比一个巨大的开关语句或几十个或数百个ifs要好得多。
至于改进,我不知道,我还在等待VS中包含各种模板和类型别名,这样我就可以进一步简化代码。
每当我看到大量重复的代码,我就开始思考类型列表和元编程,让编译器来完成工作,而不是无聊的程序员。最棒的部分呢?您在运行时得到零惩罚,它与ifs一样有效(如果您小心内联的话)
https://stackoverflow.com/questions/5578607
复制相似问题