2011-04-07 69 views
1

我对类型列表感兴趣。 在这个URL http://drdobbs.com/184403813有一个如何使用类型列表创建访问者模式的很好的例子。类型列表访客模式示例

我对这个例子有两个问题。我的两个问题在本主题的末尾。

代码如下考虑:

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"; 
    } 
} 

此代码的incovenients根据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和一个虚函数。所以我不太明白引入类型列表的好处吗?

2 - 在本文Alexandrescu的给予一定的结束建议,以改善这个代码,但我没有看得很清楚如何实现这些,可能有人能帮助我在这?

谢谢

+0

你可以看看洛基库,你会发现类型串的完整implentation。另外这本书可以帮助:http://www.amazon.co.uk/Modern-Design-Applied-Generic-Patterns/dp/0201704315 – 2011-04-07 09:26:40

回答

4

如果您有50个DocElement类型,该怎么办?在第一个例子中,你需要50个if语句,第二个例子中,你只需要一个50个元素的类型列表。

你也可以想想,当你添加其他DocElement会发生什么。在第一个例子中,你需要去改变if-else语句。使用类型列表,您可以将新类型添加到类型列表的末尾。

类型列表代码可能看起来像一个很大的开销,但是你写了一次,然后你只是使用它,而不是添加ifs或案例和代码(随着时间的推移可能会变得很大),你只需添加类型到类型列表。从维护的角度来看,类型列表代码远胜于一个巨大的switch语句或几十个或几百个ifs。

至于改进,我不知道,我还在等待可变参数模板和类型别名被列入VS,这样我可以更加简化代码。

每当我看到重复的代码一大堆,我开始思考类型列表和元编程,让编译器做的工作,而不是无聊的程序员。最好的部分?您在运行时获取零罚款,它只是作为IFS为有效(如果你使用内联小心)

+0

是的,但与第二个版本则还必须添加50种访问方法每次用一个不同的参数能够处理新的元素。但事实上也许有更好的类型列表,我不知道,因为如你所说有实施类型列表的巨大开销 – Guillaume07 2011-04-07 09:51:37

+1

是的,你将不得不添加访问方法,但海事组织仍然比添加方法更容易改变一个if/switch,它需要较少的思考。也许我在想这种方式,因为我主要是维护代码。我一直希望最初的开发人员使用类型列表而不是大量的if-elses块(我已经看到交换机可以存储超过1000行)。 – 2011-04-07 10:34:50

+0

除了O(n)dynamic_casts对我来说是一个巨大的代码味道。 – 2011-04-07 13:18:04