functon
functon

Reputation: 23

function array with functions from different objects

I don't have much experience using array of functions in C++. I need to use an array of functions where the array contains functions from different objects. Here is some dummy code to illustrate what I want to implement.

class base_class
{
public:
  virtual int function1(int arg1, int arg2);
  virtual int function2(int arg1, int arg2);
};

class derived_class : public base_class
{
public:
  int function1(int arg1, int arg2) { /* ... */ };
  int function2(int arg1, int arg2) { /* ... */ };
  // ...
};

typedef int (*functions) (int arg1, int arg2); 

int main()
{
  derived_class object1;  
  derived_class object2;  

  functions func_instance[4];
  func_instance[0] = object1.function1;
  func_instance[1] = object1.function2;
  func_instance[2] = object2.function1;
  func_instance[3] = object2.function2;
  // ...
}

I can't get it to work, it throws following error:

error: argument of type int () (int , int) does not match int (*) (int, int)

Upvotes: 2

Views: 2547

Answers (1)

pmr
pmr

Reputation: 59841

The easiest way is to use std::function and std::bind.

#include <functional>
#include <array>

derived_class object1;
derived_class object2;

std::array< std::function<int(int, int)>, 2> > 
  arr = {{ std::bind(&derived_class::function1, &object1)
         , std::bind(&derived_class::function2, &object1)}};
         // and so on

Note that object1 and object2 have been bound by address. You need to keep them alive as long as the bound functions are alive. If you just write object1 in the bind expression a copy of the object will be stored in the bound function and no scope problems will occur.

C++03 A complete example with a hand-rolled, single-purpose binder-type:

#include <iostream>

struct base
{
  virtual void f0() { std::cout << "f0 base" << std::endl; }
  virtual void f1() { std::cout << "f1 base" << std::endl; }
};

struct derived : base
{
  void f0() { std::cout << "f0 derived" << std::endl; }
  void f1() { std::cout << "f1 derived" << std::endl; }
};

// typedef for a Pointer to a member function 
// of base that accepts arguments and returns void
typedef void (base::*MemberPtrType)(void);

// we pack a pointer to a class and a pointer to a member function together
struct binder
{
  MemberPtrType ptr;
  base*         base;

  // shortcut to call this thing, you might also want 
  // to have an overload of operator() and a result_type typedef
  void call()
  { ((base)->*(ptr))(); }
};


int main()
{
  base b;
  derived d;

  // initialize a 4 element array of binder, the first argument is the function,
  // the second is the object to call it on
  // 
  // remember that b and d need to be alive as long as 
  // you want to call something in this array
  binder arr[4] = { {&base::f0, &b}, {&base::f1, &b}, 
                    {&base::f0, &d}, {&base::f1, &d}};

  // now walk through the array and call each
  for(binder* begin = arr; begin != arr + 4; ++begin)
  {
    begin->call();
  }


  return 0;
}

Upvotes: 9

Related Questions