キャストの難しさ: Void* とメンバー関数へのポインタ
プログラミングの領域では、特に、異なるデータ型間のキャストには課題が生じることがよくあります。メンバー関数へのポインターを扱うとき。この記事では、Lua インタプリタと連携する C ライブラリを作成しようとしたときに発生した問題について詳しく説明します。この問題では、void* をメンバ関数へのポインタに変換することが大きなハードルとなりました。
問題のコードは、 C オブジェクトを LuaObject として作成し、そのオブジェクトにメンバー関数を追加します:
template <class T> LuaObject<T> lobj = registerObject(L, "foo", fooObject); lobj.addField(L, "bar", &Foo::bar);
ただし、問題の原因となる次の関数:
template <class T> int call_int_function(lua_State *L) { // problematic line void (T::*method)(int, int) = reinterpret_cast<void (T::*)(int, int)>(lua_touserdata(L, lua_upvalueindex(1))); T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1)); (obj->*method)(lua_tointeger(L, 2), lua_tointeger(L, 3)); return 0; }
問題はコンパイラの不満にあります。 void をメンバー関数へのポインターにキャストすることはできません。メンバーへのポインターは固有であり、void.
のような通常のポインターに直接変換することはできません。この問題を解決するには、メンバーへのポインターを使用する代わりに、メンバー関数を通常の関数でラップすることが解決策です。このアプローチには、最初の引数としてオブジェクトを受け取り、メンバー関数を内部で呼び出す自由関数の作成が含まれます。
このアプローチを使用した関数の修正バージョンを次に示します。
template <class T> int call_int_function(lua_State *L) { void (*method)(T*, int, int) = reinterpret_cast<void (*)(T*, int, int)>(lua_touserdata(L, lua_upvalueindex(1))); T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1)); method(obj, lua_tointeger(L, 2), lua_tointeger(L, 3)); return 0; }
ラップすることによりメンバー関数を使用する場合、void* をメンバー関数へのポインターにキャストする必要がなくなり、これら 2 つのデータ型の間でキャストする際に発生する問題が解決されます。
以上がC で void* をメンバー関数へのポインターに安全にキャストする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。