使用boost绑定/函数创建菜单处理程序

时间:2013-10-15 11:00:11

标签: c++ boost-bind

我想创建一个菜单处理程序来替换这样的结构:

void MyClass::handleMenu(MenuID id) {
  switch (id) {
    case option1:  doFunction1(); break;
    case option2:  doFunction2(true); break;
    case option3:  memberVariable->doOtherFunction(); break;
  }
}

随着菜单项数量的增加,switch语句也在增长,所以我想更改为一种机制,其中菜单设置了许多函数对象,这些函数对象是响应菜单通知而调用的。一些函数可能采用其他参数(在设置时已知),有些可能是成员函数的调用。

我觉得应该看起来像这样:

 void MyClass::setupMenu() {
   std::map<MenuID, boost::function<void()>>  idMap;
   idMap[option1] = boost::bind(&MyClass::doFunction1, _1, this);
   idMap[option2] = boost::bind(&MyClass::doFunction2, _1, this, true);
   idMap[option3] = boost::bind(&MemberClass::doOtherFunction, _1, memberVariable);
 }

 void MyClass::handleMenu(MenuID id) {
   auto f=idMap[id];
   f(); // invoke callback     
 }

但是,我无法正确组合boost::function类型和bind调用。也许由于某些函数可能返回一个值而变得复杂,但在菜单处理代码中我们并不关心这一点,我们可以将其视为无效。编译器错误往往在将bind的结果插入映射的调用中。我错过了一种更简单的方法吗?

编辑:

@ frank的方法有效,但我发现了一个我没想到的问题:如果你试图通过调试器中的代码来找到由菜单项执行的函数,那么这很难,因为你有在进入实际的函数调用之前,进出几个boost::bind代码层。令人遗憾的是,调试器还没有完全跟上boost和tr1的前沿。

1 个答案:

答案 0 :(得分:2)

C ++成员函数的第一个参数是this-pointer。

boost :: bind使函数对象形成一个函数指针及其传递的参数。 _1,_2 ......是占位符(lambdas)。它们将在调用函数对象时传递。

class MyClass{
  /// Callback signature for calling the function for a specific command.
  typedef boost::function<void ()> TMenuCmdCallback;
  int doFunction1(bool);
  void doFunction2();
  double doFunction3(int);
  void setupMenu(){
    TMenuCmdCallback callback;
    m_Callbacks[ 1] = boost::bind(&MyClass::doFunction1, this, true);  // allways pass true
    m_Callbacks[10] = boost::bind(&MyClass::doFunction1, this, false); // allways pass false
    m_Callbacks[ 2] = boost::bind(&MyClass::doFunction2, this);
    m_Callbacks[ 3] = boost::bind(&MyClass::doFunction3, this, this->m_Int);
  }
  void callFunction(int index)
  {
    m_Callbacks[index]();
  }
  std::map<int, TMenuCmdCallback> m_Callbacks;
  int m_Int;
};

在我的示例中,我不检查索引是否超出范围。 在这个例子中,我也不需要lambda,因为在运行时(在callFunction中)我没有要传递的参数。

我不确定函数3的回调是否真的有效(但它至少可以编译)。

相关问题