How to do a simple C++ generic callback?

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.

Answers


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.


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.


Need Your Help

Why so big difference in sizes of almost identical documents

pdf fonts pdf-generation embedded-fonts libharu

Have two pdfs, first created with libharu and second created with PDF::API2. If not mention to coordinates then content is the same. But first pdf oversize second by four times. Only one distinctio...

SSH: Given a public/private key pair in host generate PuTTY's Pagent necesary files

ssh key rsa putty public

I want to access to a server (hosted in Lonex) trough SSH (for file handling). For this I use PuTTY. To do so safely, I use Pagent, it needs a public and a private key. In the server, under the ssh

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.