Question

I want to create a menu handler to replace a construct like this:

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

As the number of menu items grows, so does the switch statement, so I want to change to a mechanism where the menu is set up with a number of function objects that are invoked in response to the menu notification. Some of the functions may take other arguments (which are known at setup time), and some may be calls for member functions.

I've got a feeling it should look something like this:

 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     
 }

However, I can't get the right combination of the boost::function type and bind invocation. Perhaps it's complicated by the fact that some of the functions may return a value, but in the menu handling code we don't care about this, we can treat it as void. The compiler errors tend to be in the call that inserts the result of bind into the map. Am I missing a simpler way to do this?

EDIT:

@frank's approach worked, but I found a problem I didn't anticipate: if you are trying to step through the code in the debugger to find the function that gets executed by the menu item then this is quite difficult because you have to step in and out of several layers of the boost::bind code before you get to the actual function invocation. It's a shame that debuggers haven't quite kept up with the bleeding edge of boost and tr1.

Was it helpful?

Solution

A C++ member function has as its first parameter the this-pointer.

boost::bind makes a function-object form a function pointer and its passed parameter. The _1, _2 ... are place-holder (lambdas). They will be passed when the function-object is called.

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;
};

In my example I do not check if the index is out of bounds. In this example also I don't need the lambdas because at run time (in callFunction) I have no parameters to pass.

I'm not sure if the the callback to the function3 really works (but it compiles at least).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top