【问题标题】:Dealing with nested callbacks处理嵌套回调
【发布时间】:2017-11-26 06:28:58
【问题描述】:

我遇到了需要处理嵌套回调的情况。请参阅Thing::process 函数。第二个g_thing.onAfterWalk() 回调永远不会被调用,因为父级回调一旦完成就会销毁它。

Thing g_thing;

void Thing::walk(int32_t x, int32_t y) {
    if (SYSTIME() > m_walkEndTime) {
        // Still walking
        return;
    }

    auto obj = g_thing.localObject();
    auto walkDuration = obj->getWalkDurationTo(x, y);
    [..]
    m_walkEndTime = SYSTIME() + walkDuration;

    [..]

    // Walk finished. Run callback
    if (m_afterWalk) {
        m_afterWalk();
        m_afterWalk = nullptr;
    }
}

void Thing::onAfterWalk(std::function<void(void)>& callback) {
    m_afterWalk = callback;
}

void Thing::process() {
    [..]
    // Store a callback and walk
    g_thing.onAfterWalk([]() {
        // Store another callback
        // After walking to 4321, 4321 do something else.
        // My actual problem... Callback within callback
        g_thing.onAfterWalk([]() { 
            std::cout << "Walking finished.\n";
        });

        // After walking to 1234, 1234 walk to 4321, 4321
        g_thing.walk(4321, 4321);
    });
    g_thing.walk(1234, 1234);
}

如何处理这种嵌套回调?

我应该创建一个std::stack 可能带有回调队列吗?最好的方法是什么?

【问题讨论】:

  • 那么,在散步之后,您希望再次调用walk
  • 基本上我想在到达第一个位置后walk到另一个位置。
  • 你不应该在走之前设置 onAfterWalk 回调吗? (在这两种情况下?)
  • @lockcmpxchg8b 好点。你是对的。我会改变的。我认为这个问题仍然是一样的。
  • 我认为这将解决您的问题。您将在第一个将回调指针设置为 null 之前完成第二个 after-walk

标签: c++ function c++11 callback


【解决方案1】:

对我有用(有一些调整:const 参数为onAfterWalk,最后std::cout.flush())。你确定你不只是丢失标准输出中的输出吗?

#include <iostream>
#include <functional>

class Thing;
extern Thing g_thing;

class Thing
{
  std::function<void(void)> m_afterWalk;
public:
  void walk()
  {
    if(m_afterWalk)
    {
      m_afterWalk();
      m_afterWalk = nullptr;
    }
  }

  void onAfterWalk(const std::function<void(void)>& callback)
  {
    m_afterWalk = callback;
  }

  void process()
  {
    // Store a callback and walk
    g_thing.onAfterWalk([]() {
        // Store another callback
        g_thing.onAfterWalk([]() {
            std::cout << "Walking finished.\n";
        });
        g_thing.walk();
    });
    g_thing.walk();
  }
};

Thing g_thing;

int main(int argc, char *argv[])
{
  g_thing.process();
  std::cout.flush();
}

产量

$ g++ -pedantic -Wall -Werror test.cpp
$ ./a.out
Walking finished.

【讨论】:

  • 我认为它对您有用,因为您立即运行这两个回调。尝试稍稍延迟呼叫每个人。见how it works
  • 时间不会影响这一点(没有其他线程)。在您的新链接中,我看到您使用了一些未在任何地方定义的新功能,例如 g_thing.localObject();。如果您在省略的部分([...])中开始任何其他步行,那么这种方法肯定不会奏效。我可能会建议粘贴有问题的整个代码,或者澄清你想要回答的问题。
  • 任何其他步行都没有开始。唯一的用法是问题中显示的这两个。其余部分仅涉及每一步更新对象位置,这就是我跳过它的原因。我会继续挖掘,因为看起来我错过了一些东西。
  • 嗯。在您对 StoryTeller 的回复中,您声明walk 不会被阻止。你能在你的问题中详细说明这一点吗?这可能会改变我对线程的假设。
  • 就像在我的 pastebin sn-p - walk 方法在实际行走完成之前返回。它确实将时间与目标位置一起设置并返回。 StoryTeller 实现需要在方法返回后进行步行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-21
  • 1970-01-01
相关资源
最近更新 更多