列出访客模式示例

时间:2011-04-07 09:06:48

标签: c++ templates typelist

我对Typelists感兴趣。 在此网址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";
    }
}

此代码的不一致是根据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给出了一些改进此代码的建议,但我不太清楚如何实现这些,有人可以帮我解决这个问题吗?

谢谢

1 个答案:

答案 0 :(得分:4)

如果您有50种DocElement类型怎么办?对于第一个示例,您需要50个if语句,第二个示例需要有50个元素的类型列表。

您还可以考虑添加其他DocElement时会发生什么。在第一个示例中,您需要更改if-else语句。使用类型列表,您只需将新类型添加到类型列表的末尾。

类型列表代码可能看起来有很多开销,但你只需编写一次,然后就可以使用它,而不是添加ifs或case和代码(随着时间的推移会变得非常大)你只需添加类型到类型列表。从维护的角度来看,类型列表代码远远好于巨大的switch语句或数十或数百ifs。

至于改进,我不知道,我还在等待可变参数模板和类型别名包含在VS中,以便我可以进一步简化代码。

每当我看到一堆重复的代码时,我就开始考虑类型列表和元编程,让编译器完成工作,而不是无聊的程序员。最好的部分?你在运行时得到零惩罚,它和ifs一样有效(如果你小心内联)