sivabudh
sivabudh

Reputation: 32635

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?

Upvotes: 4

Views: 1757

Answers (9)

sivabudh
sivabudh

Reputation: 32635

So inspired by David Roriguez's answer, I tried it out on my own and, yup, it works:

Here's an example (stupid) code of the "modern" way to pass a function as a function parameter:

#include <functional>    
#include <assert.h>

class Command
{
public:
  static int getSeven(int number_)
  {
    return 7 + number_;
  }
  static int getEight(int number_)
  {
    return 8 - number_;
  }
};

int func(std::tr1::function<int (int)> f, int const number_ )
{
  int const new_number = number_ * 2;
  int const mod_number = f(new_number);
  return    mod_number - 3;
}


int main()
{
  assert( func(Command::getSeven, 5)  ==  14 );
  assert( func(Command::getEight, 10) == -15 );

  return 0;
}

I tried this on VS2008 with Intel C++ Compiler 11.1 with C++0X support on (don't know if C++0x support is really needed since it's in TR1).

Upvotes: 0

ryaner
ryaner

Reputation: 3997

Another way to do this if you don't have access to tr1 or boost, is just to use function template. It's quite simple and obviously a C++ way.

Here's a compilable example similar to yours:

#include <iostream>
using namespace std;

class CommandHandler
{
public:
   static void command_one(int i) { cout << "command_one " << i << endl; }
   static void command_two(int i) { cout << "command_two " << i << endl; }
};

template <typename Func>
void CommandCaller(Func f)
{
   f(1);
}

int main()
{
   CommandCaller(&CommandHandler::command_one);
   return 0;
}

Upvotes: 3

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
}

Upvotes: 5

thyrgle
thyrgle

Reputation:

I posted a question very similar to this and this was the explanation I got:

Function Pointers

And here is the link to the question I posted: Function callers (callbacks) in C?

Upvotes: 4

sth
sth

Reputation: 229593

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

Upvotes: 6

Jay
Jay

Reputation: 14471

I can think of two ways.

  1. The C style way: pass the function to be called in as a function pointer.
  2. The C++ way: create a base class that implements your code and replace the called function with a virtual method. Then derive two concrete classes from the base class, each one implementing the virtual function differently.

Upvotes: 2

renick
renick

Reputation: 3881

see this please http://www.newty.de/fpt/fpt.html

Upvotes: 1

fredoverflow
fredoverflow

Reputation: 263128

void Refactored_CommandUser(static void (*func)(Item))
{
    // some code A

    func(item);

    // some code B
}

void CommandOne_User()
{
    Refactored_CommandUser(&CommandHandler::command_one);
}

void CommandTwo_User()
{
    Refactored_CommandUser(&CommandHandler::command_two);
}

Upvotes: 0

EFraim
EFraim

Reputation: 13028

Static member functions can be passed simply as function pointers.

Non-static can be passed as member-function pointer + this.

Upvotes: 0

Related Questions