2

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

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调用的正确组合。也许有些函数可能会返回一个值,这很复杂,但是在菜单处理代码中我们并不关心这个,我们可以将其视为 void。编译器错误往往出现在将结果bind插入映射的调用中。我错过了一种更简单的方法吗?

编辑:

@frank 的方法有效,但我发现了一个我没有预料到的问题:如果您试图单步调试器中的代码以找到由菜单项执行的函数,那么这非常困难,因为您必须介入boost::bind在您进行实际的函数调用之前,请先跳过几层代码。很遗憾,调试器没有完全跟上 boost 和 tr1 的前沿。

4

1 回答 1

2

C++ 成员函数的第一个参数是 this 指针。

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 中)我没有要传递的参数。

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

于 2013-10-15T12:23:00.680 回答