我想创建一个菜单处理程序来替换这样的结构:
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的前沿。
答案 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的回调是否真的有效(但它至少可以编译)。