2011-04-07 72 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