类型列表访客模式示例

发布于 2024-10-30 19:06:48 字数 3532 浏览 1 评论 0原文

我对 Typelists 感兴趣。 在此 URLhttp://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 给出了一些改进此代码的建议,但我不太清楚如何实现这些建议,有人可以帮助我吗?

谢谢

I'm interested in Typelists .
At this URLhttp://drdobbs.com/184403813 there is a good example of how using Typelists for creating a visitor pattern.

I have two questions about this example. My two questions are at the end of this topic.

Consider the code below :

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

the incovenients of this code is according to Alexandrescu are:

In addition to being thoroughly ugly, the code above has the conceptual problem of being unable to catch at compile time the "forgot to handle this type"

So are coming typelists :

    #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- We still have dynamic_cast and a virtual function. SO I don't see well the benefict of having introduce typelists ?

2- At the end of this article Alexandrescu give some advises to improve this code , but I don't see very well how to implement these, could someone can help me on this ?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

镜花水月 2024-11-06 19:06:48

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

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

类型列表代码可能看起来有很多开销,但是您编写一次,然后只需使用它,而不是添加 ifs 或 case 和代码(随着时间的推移,它们可能会变得相当大),您只需向类型添加类型-列表。从维护的角度来看,类型列表代码远比庞大的 switch 语句或数十或数百个 if 更好。

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

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

What if you have 50 DocElement types? With the first example you need 50 if statements, with the second, you just need to have a typelist of 50 elements.

You can also think about what happens when you add another DocElement. In the first example, you need to go and change the if-else statements. With type-lists you can just add the new type to the end of the type-list.

The type-list code may seem like a lot of overhead, but you write it once, then you just use it, and instead of adding ifs or cases and code (which can get quite large over time) you just add types to the type-list. From a maintenance perspective the type-list code is far better than a huge switch statement or tens or hundreds of ifs.

As for improvements, I don't know, I'm still waiting for variadic templates and type aliases to be included in VS so that I can simplify the code even more.

Whenever I see a huge pile of repeating code, I start thinking about type-lists and metaprogramming, let the compiler do the work, not bored programmers. And the best part? You get zero penalty at runtime, it's just as efficient as the ifs (if you're careful with inlining)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文