我有一个班级:
class C {
public:
int func1 (int arg1, int arg2) { return 1; }
float func2 (float arg1, float arg2) { return 2; }
} ;
我想为方法func1和func2创建一个C包装函数,然后将其转换为void函数指针。
typedef void (*Function)(void);
typedef Function *FunctionPtr;
FunctionPtr functions[] = {
(FunctionPtr)&Wrap<&C::func1>::f,
(FunctionPtr)&Wrap<&C::func2>::f
};
之后我可以将它们转换回C函数指针并使用它们:
Class C c;
typedef int (*MyIntFunction)(C *c, int arg1, int arg2);
MyIntFunction *mif = (MyIntFunction *)functions[0];
int ri = (*mif)(&c, 1, 2);
typedef float (*MyFloatFunction)(C *c, float arg1, float arg2);
MyFloatFunction *mff = (MyFloatFunction *)functions[1];
float rf = (*mff)(&c, 1, 2);
我一直在试验各种模板魔法,但到目前为止还没有找到正确的方法。
答案 0 :(得分:4)
您可以不使用C代码中的类或模板。要包装C ++函数,您必须为每个C ++函数创建一个C包装器。在标题中:
#ifdef __cplusplus
extern "C" {
#endif
int C_func1( void *obj, int arg1, int arg2 );
#ifdef __cplusplus
}
#endif
在.cpp
:
#ifdef __cplusplus
extern "C" {
#endif
int C_func1( void *obj, int arg1, int arg2 ) {
C *const that = static_cast<C*>(obj);
return that->func1( arg1, arg2 );
}
#ifdef __cplusplus
}
#endif
重复C::func2
,依此类推。
答案 1 :(得分:0)
好的,我将发布我的“不太好解决方案”的答案。我真的希望得到比我更好的东西。
template<typename R, typename C, typename... A>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C, typename... A>
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...))
{
return MemberFunctionPointer<R,C,A...>{};
}
template<typename M, M m, typename... A>
class WrapMemberFunction
{
typedef typename decltype(inferMemberFunctionPointer(m))::Class T;
typedef typename decltype(inferMemberFunctionPointer(m))::Return R;
public:
static R f (T *t, A... args) {
return (t->*m)(args...);
}
} ;
#define WrapMember(TM) (FunctionPtr)&WrapMemberFunction<decltype(&TM), &TM>::f
#define WrapMemberA(TM, args...) (FunctionPtr)&WrapMemberFunction<decltype(&TM), &TM, args>::f
我相信这会导致编译器:
你可以写下这样的话:
FunctionPtr f = WrapMember(MyClass::MyFunction);
不幸的是,在我的方法中,宏是必要的,我不喜欢。
我已经尝试了很多东西来摆脱这个宏..无济于事,比如这个:
template<typename R, typename C, typename... A>
constexpr auto binderX(R (C::*m)(A...))
{
typedef decltype(m) M;
return &WrapMemberFunction<M, m, A...>::f;
}
FunctionPtr _x = binderX(&SimpleVector::printOther);
答案 2 :(得分:0)
经过多次测试后,我认为,最简单的方式是实现我想要的最简单方式:
template<typename M, M m, typename T, typename... A>
class WrapMemberFunctionV
{
public:
static void f (T *t, A... args) {
(t->*m)(args...);
}
} ;
template<typename M, M m, typename R, typename T, typename... A>
class WrapMemberFunction
{
public:
static R f (T *t, A... args) {
return (t->*m)(args...);
}
} ;
template<typename M, M m, typename R, typename C, typename... A>
constexpr auto generateCompileTimeWrapper(R (C::*method)(A...))
{
return &WrapMemberFunction<M, m, R, C, A...>::f;
}
template<typename M, M m, typename C, typename... A>
constexpr auto generateCompileTimeWrapper(void (C::*method)(A...))
{
return &WrapMemberFunctionV<M, m, C, A...>::f;
}
#define WrapMethod(TM) generateCompileTimeWrapper<decltype(&TM), &TM>(&TM)
像这样使用:
auto m = WrapMethod(MyClass::myMethod);
出于我的目的,我需要检测是否有返回值。 (而不是无效)。如果您不需要特殊代码,可以删除WrapMemberFunctionV并使用另一个。无回报(无效)和价值回报。