首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在VisitorPattern中合并访问者

在VisitorPattern中合并访问者
EN

Stack Overflow用户
提问于 2020-01-01 13:44:22
回答 2查看 201关注 0票数 2

我根据cpppaterns.com实现了访问者模式,以遍历一棵树并根据节点类型应用特定的操作。--我总是需要以相同的顺序遍历树,因此我将决定下一步访问哪个子节点的逻辑移到基类Visitor中。单独的访问者在树节点上执行特定的操作,然后在基本的visit中调用Visitor方法。到目前为止效果还不错。

在某些情况下,需要在一棵树上的多个访问者(例如VisitorRewriteXVisitorPrintX)之间执行实现的操作。天真的方法是只按顺序执行访问者。但是,这需要多次遍历树,这是效率低下的。

当然,我也可以创建一个新的访问者(例如,VisitorRewritePrintX),它只调用另外两个访问者--但我认为这不是干净的代码,也不灵活。有什么更通用的方法(例如,模式)可以帮助我以某种方式允许在不同的访问者中实现的动作“堆叠”?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-01 14:12:59

您可以使用多种方法,其中一种方法是有一个通用的访问者,您可以为其注册每次访问时调用的处理程序:

代码语言:javascript
运行
复制
struct visitor {

    visitor(std::initializer_list<std::function<void(int)>> cbs) : callbacks(cbs) {

    }

    void visit(int val) {
        for( auto &cb: callbacks ) {
            cb(val);
        }
    }

    std::vector<std::function<void(val)>> callbacks;
};

由于有不同元素的visit函数,因此可能需要将其更改为具有相应成员函数的类,而不是使用std::function

另一种方法是使用各种模板参数:

代码语言:javascript
运行
复制
struct handler_a {
    static void visit(int val) {
        std::cout << "handler_a: " << val << std::endl;
    }
};

struct handler_b {
    static void visit(int val) {
        std::cout << "handler_b: " << val << std::endl;
    }
};

template <class ...Handlers>
struct visitor {

    void visit(int val) {
        (Handlers::visit(val), ...);
    }
};

int main() {
    visitor<handler_a,handler_b> v;
    v.visit(10);
    return 0;
}

多样性方法的优点是没有循环,因为编译器在编译时为调用创建代码。但是它的缺点是在遍历这些处理程序时不能保存临时信息,因为这些是静态函数。但是,您也许可以通过一个上下文对象来解决这个问题,这个上下文对象与遍历对象一起传递。

如果需要,可以将访问者集化名为using visitor_a_b = visitor<handler_a,handler_b>

为了使代码最小化,我省略了继承,因此您需要将它们添加回以使virtual void accept(visitor& v) override工作。

票数 3
EN

Stack Overflow用户

发布于 2020-01-01 14:14:50

基本上,我会做这样的事情:

代码语言:javascript
运行
复制
struct IVisitor
{
    virtual ~IVisitor() = default;

    virtual void visit(NodeA&) = 0;
    virtual void visit(NodeB&) = 0;
    // ...
};


struct ITraversal : IVisitor
{
    // Traversal logic
    void visit(NodeA& n) final { visit(n.left); action(n); visit(n.right); }
    void visit(NodeB& n) final { action(n); visit(n.next); }
    // Actions
    virtual void action(NodeA&) = 0;
    virtual void action(NodeB&) = 0;

// ...
};

struct VisitorRewriteX : ITraversal
{
    void action(NodeA&) override;
    void action(NodeB&) override;
    // ...
};
struct VisitorPrintX : ITraversal
{
    void action(NodeA&) override;
    void action(NodeB&) override;
    // ...
};

// To allow type T with generic action
template <typename T>
struct VisitorT : ITraversal
{
    VisitorT() = default;
    VisitorT(const T& t) : t(t) {}

    void action(NodeA& n) override { t.action(n); }
    void action(NodeB& n) override { t.action(n); }
    // ...
    T t;
};

template <typename ... Ts>
struct Combine
{
    Combine() = default;
    Combine(Ts... args) : visitors{args...} {}

    template <typename Node>
    void action(Node& n) override {
        std::apply([&](auto&...visitor){ (visitor.action(n), ...); }, visitors);
    }
private:
    std::tuple<Ts...> visitors;
};

然后使用任何一种

VisitorRewriteXVisitorPrintXVisitorT<Combine<VisitorRewriteX, VisitorPrintX>>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59553046

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档