C ++ 클래스 멤버 함수를 C 콜백 함수로 사용
문제
일부 처리를 사용자 정의하기 위해 등록하려면 콜백 함수가 필요한 C 라이브러리가 있습니다. 콜백 함수의 유형입니다 int a(int *, int *)
.
다음과 유사한 C ++ 코드를 작성하고 C ++ 클래스 기능을 콜백 함수로 등록하려고합니다.
class A {
public:
A();
~A();
int e(int *k, int *j);
};
A::A()
{
register_with_library(e)
}
int
A::e(int *k, int *e)
{
return 0;
}
A::~A()
{
}
컴파일러는 다음 오류를 던집니다.
In constructor 'A::A()',
error:
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’.
내 질문 :
- 우선 내가하려는 것처럼 C ++ 클래스 Memeber 기능을 등록 할 수 있습니다. 그렇다면 어떻게해야합니까? (나는 32.8 at을 읽었다 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html. 그러나 내 생각에 그것은 문제를 해결하지 못한다)
- 이것을 다루는 대체/더 좋은 방법이 있습니까?
해결책
멤버 함수가 정적 인 경우 그렇게 할 수 있습니다.
클래스 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) {
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 );
따라서 클래스 인스턴스를 인수로 전달할 수 없기 때문에 통과 할 수 없습니다. 작업하는 한 가지 방법은 방법을 정적으로 만드는 것입니다.이 방법은 좋은 유형을 가질 것입니다. 그러나 클래스 인스턴스는 아니며 비 정적 클래스 멤버에 대한 액세스가 아닙니다.
다른 방법은 처음으로 A에 대한 정적 포인터가있는 함수를 선언하는 것입니다. 함수는 클래스로 호출을 리디렉션합니다.
int callback( int *j, int *k )
{
static A *obj = new A();
a->(j, k);
}
그런 다음 콜백 함수를 등록 할 수 있습니다.
글쎄 ... 만약 당신이 Win32 플랫폼에 있다면 항상 불쾌한 멍청한 길이 있습니다 ...
Win32의 Thunking : 비 정적 멤버 함수로 콜백을 단순화합니다.
솔루션이지만 사용하지 않는 것이 좋습니다.
그것은 좋은 설명을 가지고 있으며 그것이 존재한다는 것을 아는 것이 좋습니다.
멤버 함수를 사용하는 데있어 문제는 행동 할 객체가 필요하고 C는 객체에 대해 알지 못한다는 것입니다.
가장 쉬운 방법은 다음을 수행하는 것입니다.
//In a header file:
extern "C" int e(int * k, int * e);
//In your implementation:
int e(int * k, int * e) { return 0; }