Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a function to a function?

Suppose I have a class with 2 static functions:

class CommandHandler
{
public:
  static void command_one(Item);
  static void command_two(Item);
};

I have a DRY problem where I have 2 functions that have the exact same code for every single line, except for the function that it calls:

void CommandOne_User()
{
  // some code A

  CommandHandler::command_one(item);

  // some code B
}

void CommandTwo_User()
{
  // some code A

  CommandHandler::command_two(item);

  // some code B
}

I would like to remove duplication, and, ideally, do something like this:

void CommandOne_User()
{
  Function func = CommandHandler::command_one();

  Refactored_CommandUser(func);
}

void CommandTwo_User()
{
 Function func = CommandHandler::command_one();

 Refactored_CommandUser(func);
}

void Refactored_CommandUser(Function func)
{
  // some code A

  func(item);
}

I have access to Qt, but not Boost. Could someone help suggest a way on how I can refactor something like this?

like image 611
sivabudh Avatar asked Dec 01 '22 10:12

sivabudh


2 Answers

You could use function pointers:

// type of the functions
typedef void Function(Item);

void CommandOne_User() {
  // function pointer
  Function *func = CommandHandler::command_one;
  Refactored_CommandUser(func);
}

void CommandTwo_User() {
  // can also be used directly, without a intermediate variable
  Refactored_CommandUser(CommandHandler::command_two);
}

// taking a function pointer for the command that should be executed
void Refactored_CommandUser(Function *func) {
  // calling the funcion (no explicit dereferencing needed, this conversion is
  // done automatically)
  func(item);
}
like image 81
sth Avatar answered Dec 05 '22 18:12

sth


Besides the C way (passing a function pointer) or the C++ way mentioned by Jay here there is the other (modern) c++ way with boost or with a compiler with c++0x support:

void Refactored_CommandUser( boost::function<void (Item)> f ) {
   // alternatively std::function with proper compiler support
}

With the advantage that this encapsulates a functor, and can be combined with boost::bind (or std::bind) to pass in not only free-function pointers that match the signature exactly, but also other things, like member pointers with an object:

struct test {
   void f( Item );
};
void foo( Item i, std::string const & caller );
void bar( Item i ); 
int main() {
   test t;
   Refactored_CommandUser( boost::bind( &test::f, &t, _1 ) );
   Refactored_CommandUser( boost::bind( foo, _1, "main" ) );
   Refactored_CommandUser( bar ); // of course you can pass a function that matches directly
}
like image 23
David Rodríguez - dribeas Avatar answered Dec 05 '22 18:12

David Rodríguez - dribeas