简体   繁体   中英

C callback using a C++ template class method

I'm trying to integrate a C library with callbacks into a templated C++ class. For simplicity say the C library operates as

utility_class data;
callback(double input[], void* data);

void* mem;
c_library_init(mem);
c_library_data(mem, &data);
c_library_callback(mem, &callback);
c_library_action(mem);
c_library_free(mem);

If I had a non-templated C++ class then this would be straightforward,

extern "C"
void callback(double input[], void* data) {
  static_cast<example>(data)->callback_impl(input);
}

class example {
private:
  void* mem_;
public:
  example(): mem_(NULL) {
    c_library_init(mem);
    c_library_data(mem, (void*)this);
    c_library_callback(mem, &callback);
  }
  ~example {
    c_library_free(mem);
  }
  void action() {
    c_library_action(mem);
  }
  void callback_impl(double input[]) {
    ...
  }
};

But if example is templated then callback doesn't know to what to cast the void pointer. Making callback a static class method,

template <class T>
class example {
private:
  void* mem_;
public:
  example(): mem_(NULL) {
    c_library_init(mem);
    c_library_data(mem, (void*)this);
    c_library_callback(mem, &example<T>::callback);
  }
  ~example {
    c_library_free(mem);
  }
  void action() {
    c_library_action(mem);
  }
  void callback_impl(double input[]) {
    ...
  }
  static void callback(double input[], void* data) {
    static_cast<example<T> >(data)->callback_impl(input);
  }
};

compiles, but the executable inevitable dies with a malloc error which I can only assume is because of a new/free conflict due to the lack of a proper extern. Defining the static method out-of-line with an explicit extern "C" yields the same behavior.

Is there any hope? Thanks!

Updated: Added the C library call to set the user data used in the callback.

How about solving this with polymorphism? With a base class like this

struct example_base {
   virtual void callback(double[]) = 0;
};

Your templated class could inherit from it like this

template <typename T>
struct example : public example_base {
    example() : mem_(nullptr) {
      c_library_init(mem_);
      c_library_data(mem_, this);
      c_library_callback(mem_, callback_dispatch);
   }
   void callback(double[]) override;

   void* mem_;
};

And the callback member function could be called with

extern "C" void callback_dispatch(double input[], void* data) {
  static_cast<example_base>(data)->callback(input);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM