简体   繁体   English

具有内部类的Lambda实现接口

[英]Lambda with inner class implementing an interface

I am not very experienced with lambdas yet but I begin to like them very much and use them where it makes sense and where I feel they are the way to go. 我对lambda的经验还不是很丰富,但是我开始非常喜欢它们,并在有意义的地方和我认为它们可以走的地方使用它们。

Anyway, I have a class Tree that has a Tree::Visitor class with one virtual callback function called visit(/*args*/) . 无论如何,我有一个Tree类,它有一个Tree::Visitor类,带有一个名为visit(/*args*/)虚拟回调函数。 That Visitor class does a recursive walk over all nodes. 该访问者类在所有节点上进行递归遍历。 With this callback I am able to collect data from each node (or better I can extract paths of the tree (which is basically what I do with this function). 通过此回调,我可以从每个节点收集数据(或者更好的是,我可以提取树的路径(这基本上就是我使用此功能所做的))。

So I take a lambda and inside I use a class to implement the visit callback function by deriving from Tree::Visitor . 因此,我使用了一个lambda,并在内部使用一个类,通过从Tree::Visitor派生实现visit回调函数。

// Tree class, a rough view how it looks
class Tree {

    // ...

    // Visitor class for recursive walking the tree
    class Visitor {
       // 
       void count(/* ... */) {
           // in here the implemented visit(/*args*/) fct is called
       }

       // ...
       void triggerVisit() { 
           // ...
           count(/* ... */);
           // ...
       }

       // visitor callback
       virtual void visit(/* args */) = 0;
    };
};

class A {
    Tree tree;
    PriorityQueue que;

    A() : tree(), que(maxEntries) {}

    // first build the tree ...
    void buildTheTree() {
        tree.buildTree();               
    }

    // walk the tree
    void visitTheTree() {

       std::shared_ptr<Tree::Visitor>(
          [&]()->Tree::Visitor * {

             // this class implements visit(/*args*/)
             class MyVisitor : public Tree::Visitor {
                 A& parent; // pointer to A

                 Myvisitor(A& p) 
                 : Tree::Visitor(p.tree), parent(p) {}      

                 // implementation
                 virtual void visit( /* args */ ) {

                     // ... get somedata 

                     if (/* condition true */) {
                         parent.que.push(somedata);
                     }
                 }  
             };

             return new MyVisitor(*this);

          }()
       )->triggerVisit();

       // get the collected data from que
       while(que.size() > 0) {
          // ...
       }
    }
};

Basically this is what I have and it is working without problems. 基本上这就是我所拥有的,并且可以正常工作。

I have a priority queue que that I use to store somedata , that are the n top scored nodes of the tree. 我有一个优先级队列que ,用于存储somedata ,它们是树的n得分最高的节点。 At this time that que is defined as a member of class A , which I dislike, because I just need to collect the data inside the visitTheTree member, so it could be rather a local variable So my question is more a question of design/style and I have the feeling I miss something with the c++11 standard (maybe). 目前,这个que被定义为A类的成员,我不喜欢它,因为我只需要在visitTheTree成员中收集数据,因此它可能是一个局部变量,所以我的问题更多是设计/样式问题而且我有一种想念c ++ 11标准的感觉(也许)。

I tried to define que inside visitTheTree() and pass it with the constructor of MyVisitor . 我试图在visitTheTree()内部定义que ,并将其传递给MyVisitor的构造MyVisitor Somehow this is not working correctly, at least I do not get proper/complete results I expect. 不知何故,这无法正常工作,至少我没有获得预期的正确/完整结果。 When I define the Priority queue variable as a member of A (as it is now) and access it with the parent pointer in MyVistor, I get proper results and all is fine. 当我将Priority队列变量定义为A的成员(如现在)并使用MyVistor中的父指针访问它时,我得到了正确的结果,一切都很好。

Is there any good way to define que locally in VisitTheTree() instead of defining it in the class A as a member? 有什么好方法可以在VisitTheTree()中本地定义que ,而不是在A类中将其定义为成员? I know I have to pass it with the constructor as I can not access variables outside the MyVistor (just like this). 我知道我必须通过构造函数传递它,因为我无法访问MyVistor之外的变量(就像这样)。

BTW, I found the question C++0x - lambda expression does look same as Java's anonymous inner class? 顺便说一句,我发现了问题C ++ 0x-lambda表达式看起来与Java的匿名内部类相同吗? which comes close to the problem/question I have. 这很接近我的问题。 Interesting is the answer from Johannes. 有趣的是约翰尼斯的答案。

Any hints or ideas would be welcome. 任何提示或想法都将受到欢迎。 Thanks for your thoughts and help! 感谢您的想法和帮助!

Andreas, I would really like to help you, but I cannot see a way to do it using your design. 安德烈亚斯,我真的很想为您提供帮助,但是我看不到一种使用您的设计的方法。 I had a similar situation using boost graph library, and I made the following (hope it helps you): 我在使用Boost图形库时遇到了类似的情况,并且做了以下工作(希望它对您有所帮助):

  • Visitor has a std::function<RET (/*args*/> member that is used to make an action every node you visit. I would also make this function a parameter for the visitor constructor. Visitor具有std::function<RET (/*args*/>成员,该成员用于对您访问的每个节点执行操作。我还将使此函数成为visitor构造函数的参数。
  • Every time you need to visit some nodes you will make it through a new instance of your visitor passing a new lambda function as the argument. 每次您需要访问某些节点时,都将通过新的lambda函数作为参数,通过访问者的新实例进行访问。

I would try to provide some example, 我会尝试提供一些例子,

class Tree {
    ...
    typedef std::function<void (/*node and args*/)> visit_fn;

    class Visitor {
        visit_fn& visitor;

        public:
            Visitor( visit_fn f ) : visitor( f ) {}
        ...
    };
};

class A {

    ...

    void visit_tree() {
        que.clear(); // could also be a local queue object

        Visitor vis([&](/*args*/) {
            que.push( some_data ); /*I have que because of & in my lambda*/
        });

        vis.triggerVisit();

        // Her I can use my queue member
    }

};

Now, if you have a commom way to visit your elements you can even pass a Functor to your Visitor, providing better code reuse. 现在,如果您有一种常用的方式来访问元素,您甚至可以将Functor传递给Visitor,从而提供更好的代码重用性。

I really think that the lambda in your design is not using the [&] binding, and in this sense could be a common function, wich I think would be more clean, reusable and efficient. 我真的认为您设计中的lambda并未使用[&]绑定,因此从某种意义上讲,它可能是一个通用功能,但我认为它将更加干净,可重用和高效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM