用c方法包装c ++方法

时间:2016-11-24 16:29:43

标签: c++ templates function-pointers

我有一个班级:

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);

我一直在试验各种模板魔法,但到目前为止还没有找到正确的方法。

3 个答案:

答案 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

我相信这会导致编译器:

  1. 推断回归和上课(显然)
  2. 创建一个专门的模板类,它具有一个调用指定成员函数的静态函数
  3. 允许将此专用模板类静态函数作为可导出的C函数引用。
  4. 你可以写下这样的话:

    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并使用另一个。无回报(无效)和价值回报。