一般的に、キャストを使用しない限り、g ++を信頼する必要があります。
あなたが言及している関数型のどれもC言語から使用するためにエクスポートすることはできませんが、これはあなたが求めているものではありません。関数ポインタとして渡すことができる関数について質問しています。
あなたが渡すことができるものに答えるには、あなたが渡せないものを理解することがより建設的だと思います。引数リストに明示的に記載されていない追加の引数を必要とするものは渡すことはできません。
したがって、非静的メソッドはありません。彼らには暗黙の "this"が必要です。 Cはそれを渡すことを知らない。次に、コンパイラはあなたにあなたを許しません。
キャプチャラムダはありません。それらは実際のラムダ本体と暗黙の引数を必要とします。
あなたが渡すことができるのは、暗黙のコンテキストを必要としない関数ポインタです。実際のところ、先に進み、それらをリストしました:
- ファンクションポインタ。テンプレートが完全に解決されている限り、それが標準機能であるかテンプレートであるかは関係ありません。これは問題ではありません。関数ポインタを使用する構文は、テンプレートを自動的に完全に解決します。
- ノンキャプチャラムダ。これは、C++ 11がlambdaを導入したときに導入された特別な回避策です。これを行うことが可能なので、コンパイラはそれを実現するために必要な明示的な変換を行います。
- 静的メソッド。静的なので暗黙的に
this
が渡されることはないため、大丈夫です。
最後に拡大しています。多くのCコールバック・メカニズムは、関数ポインタとvoid * opaqを取得します。
class Something {
void callback() {
// Body goes here
}
static void exported_callback(void *opaq) {
static_cast<Something*>(opaq)->callback();
}
}
そして実行します:
編集を追加する
Something something;
register_callback(Something::exported_callback, &something);
次はC++クラスでそれらを使用しての標準とかなり安全であるこの作品 唯一の理由は、C++で暗黙の引数が渡されない場合、呼び出し規約とC呼び出し規約は同一です。ネームマングリングには違いがありますが、ネームマングリングの唯一の目的はリンカが正しいファンクションのアドレスを見つけることができるためです。
このトリックでは、たとえばstdcallやpascalの呼び出し規約を想定してコールバックを試していたのですが、このスキームは面倒になります。
これは静的メソッド、ラムダ、およびテンプレート関数に固有のものではありません。たとえ標準的な機能であっても、そのような状況では失敗します。悲しいことに
、あなたはstdcallの型に関数ポインタを定義するとき、gccはあなたを無視します:
#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);
結果で:
test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
typedef stdcall void (*callback_type)(void *);
_ "CとC++の関数に異なる呼び出し規約と言語バインディングが使用されている場合、安全に疑問があります。" - すべてがターゲット環境用に一貫してコンパイルされている場合、これらのような違いはありません。 –
スタティックメンバ関数、特殊なテンプレート関数、非キャプチャラムダにextern "C"呼び出し規約を与えることはできません。しかし、実際にはコンパイラによって異なります。実際に問題として、主な問題は動作しないのではなく、一部のコンパイラが正式版について愚かな警告を発することがあるということです。 –
@ Cheersandhth.-Alf、それは問題ではありません。 Cライブラリは、問題なくC++コンパイラによって名前が変更された関数を呼び出すことができるはずです。 –