maverik
maverik

Reputation: 5586

Bind class member to plain-C function pointer

I have a library which sources I may not change. It has a structure that contains function pointer which is a callback for some event. Consider:

// library code (.h file)

typedef int (callback_function)(int arg1, double arg2);

struct callbacks_struct
{
    ...
    callback_function *callback;
    ...
};

I'm writing a C++ wrapper for this low-level stuff. Consider I have a class:

class Wrapper
{
public:
    int Callback(int arg1, double arg2);
};

Now I want to bind Wrapper::Callback to be used as a callback when creating structure callback_struct:

struct callback_struct x[] = 
{
    {
        ...
        // put a Wrapper::Callback as a callback
        ...
    },
    {0, 0, 0, 0}
}

Obviously, this can not be done without some intermediate function. The one way is to make a global object of Wrapper class and use it:

std::shared_ptr<Wrapper> gWrapper;

void foo()
{
    struct callback_struct x[] = 
    {
        {
            ...
            my_plain_callback,
            ...
        },
        {0, 0, 0, 0}
    }
}

int my_plain_callback(int arg1, double arg2)
{
    return gWrapper->Callback(arg1, arg2);
}

But I need a thread-safe solution, so using global variable seems to be a source of problems in this case.

Does anyone know better solution?

Thanks.

Upvotes: 1

Views: 529

Answers (2)

Naszta
Naszta

Reputation: 7744

It may help you:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <stdexcept>
#include <mutex>

class Wrapper
{
  typedef std::mutex mutex_type;
  typedef std::unique_lock<mutex_type> locker;
public:
  typedef boost::function<int(int,double)> call_backtype;
  static int callBackFunction(int arg1_, double arg2_)
  {
    locker l(_mutex);
    if ( my_call.empty() ) {
      throw std::runtime_error("No callback function was set!");
    }
    return my_call(arg1_,arg2_);
  }
  static void setCallBack( const call_backtype& func_ )
  {
    locker l(_mutex);
    _my_call = func_;
  }
private:
  static mutex_type _mutex;
  static call_backtype _my_call;
  Wrapper(void){}
};

class any_other_class
{
  int do_anything(int arg1_, double arg2_);
  void setThisAsCallback()
  {
    Wrapper::setCallBack(boost::bind(&any_other_class::do_anything,this,_1,_2));
  }
};

// to C interface (use the static method):
setCallBack(&Wrapper::callBackFunction);

Upvotes: 1

Sebastian Redl
Sebastian Redl

Reputation: 71989

Use a thread-local variable for the callback state.

Or go the hardcore route and use some platform-dependent code to generate a stub that injects the pointer.

Upvotes: 2

Related Questions