2016-11-24 14 views
1

持つ方法私はクラスを持っている:ラップC++ Cメソッド

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

を、これまでのところ、これを行うための正しい方法を発見していません。

+2

Cでクラスをどのように宣言すると思いますか? –

+1

データポインタへのキャスト関数ポインタ( 'void *')は未定義の動作です。 – StoryTeller

+0

なぜこれをやりたいのですか?共有ライブラリを作成し、基礎となる 'C++ '実装への' C'インタフェースを必要としていますか? – Chad

答えて

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ため、など。

+0

これらのラッパー関数の作成を簡略化するために、可変引数リストを持つマクロを使用することもできます。 –

+1

@ Ville-ValtteriTiittanenあなたはマクロの4つのバージョンが必要になります:(1)no-argsでのノーリターン(2)no-args(3)でのノーリターンとargs(4) –

+0

これは "c関数を使ってC++関数のラッパーを作成する"ための解決策ですが、とにかくテンプレートの魔法を使って "自動化"しません。私は "(FunctionPtr)&Wrap <&C::func1> :: f"というような解決策を探しています。 (私が質問の2番目の文で述べたように)。私はC++コードで関数テーブルを作成し、この関数テーブルをCコードで使用します。 - これを正解とマークしません。 – iamacomputer

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関数として参照できるようにします。

そして、あなたはのようなもの書くことができます:私のアプローチでは残念ながら

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

実際にこれらのラップされた機能の1つを呼び出そうとしましたか?それは実際に動作しますか? –

+0

はい。彼らが働きます。 – iamacomputer

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

、私はそこにあるかどうかを検出する必要があります戻り値(voidの代わりに)。このために特別なコードが必要ない場合は、WrapMemberFunctionVを削除して、他のコードを使用することができます。ノーリターン(void)と値リターンの両方に対して。

関連する問題