2

Say I have the following code:

class A
{
public:
    A() {}

    int f(void*, void*)
    {
        return 0;
    }
};

template <typename T>
class F {
public:
    F(int(T::*f)(void*,void*))
    {
        this->f = f;
    }

    int(T::*f)(void*,void*);

    int Call(T& t,void* a,void* b)
    {
        return (t.*f)(a,b);
    }
};

A a;
F<A> f(&A::f);
f.Call(a, 0, 0);

Well this works I can call the function easily but how would I for example have an array of these without knowing the type?

I would like to be able to call any class f function as a callback. I'd normally use a static or c function and be done with it but I wanted to experiment with calling a C++ member function.

Think of what I'm trying to do as delegates in C#. I've seen very sophisticated implementations in Boost and other places but I want the bare minimum, no copying, creation, deletion etc required just a simple callback that I can call.

Is this a pipedream? Any advice would be appreciated.

user2343987
  • 23
  • 1
  • 3
  • 8
    You should look up [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind), and maybe [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function). – Some programmer dude May 02 '13 at 16:41
  • possible duplicate of [Callback functions in c++](http://stackoverflow.com/questions/2298242/callback-functions-in-c) –  May 02 '13 at 16:43
  • 1
    if you are limited to C++03, boost::function and boost::bind can be used – mirk May 02 '13 at 16:44
  • Why on Earth are you using void? Use the compilers ability to use types/ – Ed Heal May 02 '13 at 17:00
  • Sorry I will probably use typename P1 and P2 eventually I just wanted something that compiled and ran for the example. – user2343987 May 02 '13 at 17:17
  • If you are using void as a parameter you are up a certain creak without a certain instrument and the air is not that fresh! – Ed Heal May 02 '13 at 17:24

2 Answers2

4

Using std::function and std::bind as I mentioned in my comment, you could do something like this:

#include <functional>

class A
{
public:
    A() {}

    int f(void*, void*)
    {
        return 0;
    }
};

class F {
public:
    F(std::function<int(void*, void*)>& func)
        : func_(func)
    { }

    std::function<int(void*, void*)>& func_

    int Call(void* a, void* b)
    {
        return func_(a, b);
    }
};

int main()
{
    using namespace std::placeholders; //for _1, _2, _3...

    A a;
    F f(std::bind(&A::f, a, _1, _2));

    f.Call(nullptr, nullptr);
}

To use a vector of those functions, simply use e.g.

std::vector<std::function<int(void*, void*)>> my_function_vector;

Then to call each function in the vector, you simply iterate over it:

for (auto& f : my_function_vector)
{
    int result = f(some_pointer_1, some_pointer_2);
}

And if you don't have the new C++11 features in the standard library, using boost::bind and boost::function works just as well. And you use the old-fashioned iterator loop to iterate over the vector instead.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I'll take a look at boost::bind and boost::function, I'm not sure I can do the same though I'm working on some old code that has to compile on a legacy system. – user2343987 May 02 '13 at 17:21
1

I think the bare minimum implementation would be the following:

std::vector<std::function<bool(int, int)>> my_delegate;

You can then add many different types of callable items to your vector. Such as:

bool mycompare(int a, int b)
{
    return a < b;
}

struct predicate
{
    bool operator()(int a, int b)
    {
        return a < b;
    }
};

struct myclass
{
    bool function(int a, int b)
    {
        return a < b;
    }
};

my_delegate.push_back(predicate());
my_delegate.push_back(mycompare);
my_delegate.push_back([](int a, int b){return a < b;});
myclass c;
my_delegate.push_back(std::bind(std::bind(&myclass::function, &c, std::placeholders::_1, std::placeholders::_2));

Calling all the functions in your delegate is just a matter of looping through them and calling each in turn.

Peter R
  • 2,865
  • 18
  • 19