Лямбда с внутренним классом, реализующим интерфейс

Я еще не очень разбираюсь с лямбдами, но я начинаю их очень любить и использую там, где это имеет смысл, и где я чувствую, что это путь.

Во всяком случае, у меня есть класс Tree это имеет Tree::Visitor класс с одной виртуальной функцией обратного вызова visit(/*args*/), Этот класс Visitor выполняет рекурсивный обход всех узлов. С помощью этого обратного вызова я могу собирать данные с каждого узла (или, что лучше, я могу извлекать пути из дерева (что в основном и делает с этой функцией).

Поэтому я беру лямбду и внутри я использую класс для реализации visit функция обратного вызова, получая из Tree::Visitor,

// 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) {
// ...
}
}
};

В основном это то, что у меня есть и работает без проблем.

У меня очередь с приоритетами que что я использую для хранения somedataэто n Лучшие узлы дерева. В это время que определяется как член класса A, что мне не нравится, потому что мне просто нужно собрать данные внутри члена visitTheTree, так что это может быть скорее локальная переменная
Так что мой вопрос больше относится к дизайну / стилю, и у меня есть ощущение, что я что-то упускаю из-за стандарта c ++ 11 (возможно).

Я пытался определить que внутри visitTheTree() и передать его с конструктором MyVisitor, Почему-то это не работает правильно, по крайней мере, я не получаю правильные / полные результаты, которые я ожидаю. Когда я определяю переменную очереди Priority как член A (как сейчас) и обращаюсь к ней с помощью родительского указателя в MyVistor, я получаю правильные результаты, и все в порядке.

Есть ли хороший способ определить que локально в VisitTheTree () вместо определения его в классе A как члена? Я знаю, что должен передать его конструктору, так как не могу получить доступ к переменным вне MyVistor (просто так).

Кстати, я нашел вопрос C ++ 0x — лямбда-выражение выглядит так же, как анонимный внутренний класс Java? которая приближается к проблеме / вопросу, который у меня есть. Интересен ответ от Йоханнеса.

Любые намеки или идеи будут приветствоваться. Спасибо за ваши мысли и помощь!

0

Решение

Андреас, я бы очень хотел помочь тебе, но я не вижу способа сделать это, используя твой дизайн. У меня была похожая ситуация с использованием библиотеки графов буста, и я сделал следующее (надеюсь, это поможет вам):

  • Посетитель имеет std::function<RET (/*args*/> член, который используется для выполнения действий на каждом узле, который вы посещаете. Я бы также сделал эту функцию параметром для конструктора посетителей.
  • Каждый раз, когда вам нужно посетить некоторые узлы, вы пройдете через новый экземпляр вашего посетителя, передав в качестве аргумента новую лямбда-функцию.

Я хотел бы привести пример,

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
}

};

Теперь, если у вас есть удобный способ посещения ваших элементов, вы даже можете передать Functor вашему посетителю, что обеспечит лучшее повторное использование кода.

Я действительно думаю, что лямбда в вашем дизайне не использует [&] связывание, и в этом смысле может быть общей функцией, которая, я думаю, будет более чистой, многоразовой и эффективной.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]