C++ クラス メンバー関数を C コールバック関数として使用する

メンバー関数が静的であれば、それを行うことができます。

クラス A の非静的メンバー関数には、型 class A* の暗黙的な最初のパラメーターがあります これに対応 ポインター。そのため、コールバックの署名にも最初のパラメーター class A* が含まれている場合にのみ登録できました。 タイプしてください。


メンバー関数が静的でない場合にもこれを行うことができますが、もう少し作業が必要です (「C++ 関数ポインターを c 関数ポインターに変換する」も参照してください):

#include <stdio.h>
#include <functional>

template <typename T>
struct Callback;

template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
   template <typename... Args> 
   static Ret callback(Args... args) {                    
      return func(args...);  
   }
   static std::function<Ret(Params...)> func; 
};

template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;

void register_with_library(int (*func)(int *k, int *e)) {
   int x = 0, y = 1;
   int o = func(&x, &y);
   printf("Value: %i\n", o);
}

class A {
   public:
      A();
      ~A();
      int e(int *k, int *j);
};

typedef int (*callback_t)(int*,int*);

A::A() {
   Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
   callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);      
   register_with_library(func);      
}

int A::e(int *k, int *j) {
   return *k - *j;
}

A::~A() { }

int main() {
   A a;
}

この例は、コンパイルするという意味で完全です:

g++ test.cpp -std=c++11 -o test

c++11 が必要です 国旗。コードでは、 register_with_library(func) が表示されます func が呼び出されます メンバー関数 e に動的にバインドされた静的関数です .


問題は、メソッド !=関数です。コンパイラはメソッドを次のように変換します:

int e( A *this, int *k, int *j );

クラスインスタンスを引数として渡すことができないため、渡すことができないことは確かです。回避策の 1 つは、メソッドを静的にすることです。これにより、適切な型が得られます。ただし、クラス インスタンスや非静的クラス メンバーへのアクセスはできません。

もう 1 つの方法は、最初に初期化された A への static Pointer を使用して関数を宣言することです。この関数は呼び出しをクラスにリダイレクトするだけです:

int callback( int *j, int *k )
{
    static A  *obj = new A();
    a->(j, k);
}

その後、コールバック関数を登録できます。